OpENer - Open Source EtherNet/IP(TM) I/O Target Stack  2.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
encap.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 <stdlib.h>
8 #include <stdbool.h>
9 
10 #include "encap.h"
11 
12 #include "opener_api.h"
13 #include "cpf.h"
14 #include "endianconv.h"
15 #include "cipcommon.h"
16 #include "cipmessagerouter.h"
17 #include "cipconnectionmanager.h"
18 #include "cipidentity.h"
19 #include "generic_networkhandler.h"
20 #include "trace.h"
21 #include "socket_timer.h"
22 #include "opener_error.h"
23 
24 /*Identity data from cipidentity.c*/
25 extern CipUint vendor_id_;
26 extern CipUint device_type_;
27 extern CipUint product_code_;
28 extern CipRevision revision_;
29 extern CipWord status_;
32 
33 /* IP address data taken from TCPIPInterfaceObject*/
35 
45 typedef enum {
48 
49 const int kSenderContextSize = 8;
52 typedef enum {
62 
64 typedef enum {
67 
68 #define ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES 2
70 #define ENCAP_MAX_DELAYED_ENCAP_MESSAGE_SIZE ( ENCAPSULATION_HEADER_LENGTH + \
71  39 + sizeof(OPENER_DEVICE_NAME) ) /* currently we only have the size of an encapsulation message */
72 
73 /* Encapsulation layer data */
74 
76 typedef struct {
78  int socket;
79  struct sockaddr_in receiver;
81  size_t message_size;
83 
85 
87 
90 
91 /*** private functions ***/
93  const EncapsulationData *const receive_data,
94  ENIPMessage *const outgoing_message);
95 
96 void HandleReceivedListIdentityCommandUdp(const int socket,
97  const struct sockaddr_in *const from_address,
98  const EncapsulationData *const receive_data,
99  ENIPMessage *const outgoing_message);
100 
102  const EncapsulationData *const receive_data,
103  ENIPMessage *const outgoing_message);
104 
106  const EncapsulationData *const receive_data,
107  const struct sockaddr *const originator_address,
108  ENIPMessage *const outgoing_message);
109 
111  const EncapsulationData *const receive_data,
112  ENIPMessage *const outgoing_message);
113 
114 int GetFreeSessionIndex(void);
115 
117  const EncapsulationData *const receive_data);
118 
119 void DetermineDelayTime(const EipByte *const buffer_start,
120  DelayedEncapsulationMessage *const delayed_message_buffer);
121 
122 /* @brief Initializes session list and interface information. */
123 void EncapsulationInit(void) {
124 
126 
127  /*initialize random numbers for random delayed response message generation
128  * we use the ip address as seed as suggested in the spec */
129  srand(interface_configuration_.ip_address);
130 
131  /* initialize Sessions to invalid == free session */
132  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; i++) {
133  g_registered_sessions[i] = kEipInvalidSocket;
134  }
135 
137  i++) {
138  g_delayed_encapsulation_messages[i].socket = kEipInvalidSocket;
139  }
140 
141  /*TODO make the interface information configurable*/
142  /* initialize interface information */
143  g_interface_information.type_code = kCipItemIdListServiceResponse;
144  g_interface_information.length = sizeof(g_interface_information);
145  g_interface_information.encapsulation_protocol_version = 1;
146  g_interface_information.capability_flags = kCapabilityFlagsCipTcp
148  snprintf( (char *) g_interface_information.name_of_service,
149  sizeof(g_interface_information.name_of_service),
150  "Communications" );
151 }
152 
154  EipUint8 *buffer,
155  size_t length,
156  int *remaining_bytes,
157  struct sockaddr *originator_address,
158  ENIPMessage *const outgoing_message) {
159  OPENER_TRACE_INFO("Handles data for TCP socket: %d\n", socket);
160  EipStatus return_value = kEipStatusOk;
162  /* eat the encapsulation header*/
163  /* the structure contains a pointer to the encapsulated data*/
164  /* returns how many bytes are left after the encapsulated data*/
165  *remaining_bytes = CreateEncapsulationStructure(buffer, length,
166  &encapsulation_data);
167 
168  if (kEncapsulationHeaderOptionsFlag == encapsulation_data.options) /*TODO generate appropriate error response*/
169  {
170  if (*remaining_bytes >= 0) /* check if the message is corrupt: header size + claimed payload size > than what we actually received*/
171  {
172  /* full package or more received */
173  encapsulation_data.status = kEncapsulationProtocolSuccess;
174  return_value = kEipStatusOkSend;
175  /* most of these functions need a reply to be send */
176  switch (encapsulation_data.command_code) {
178  OPENER_TRACE_INFO("NOP\n");
179  /* NOP needs no reply and does nothing */
180  return_value = kEipStatusOk;
181  break;
182 
184  OPENER_TRACE_INFO("List services\n");
185  HandleReceivedListServicesCommand(&encapsulation_data,
186  outgoing_message);
187  break;
188 
190  OPENER_TRACE_INFO("List identity\n");
191  HandleReceivedListIdentityCommandTcp(&encapsulation_data,
192  outgoing_message);
193  break;
194 
196  OPENER_TRACE_INFO("List interfaces\n");
197  HandleReceivedListInterfacesCommand(&encapsulation_data,
198  outgoing_message);
199  break;
200 
202  OPENER_TRACE_INFO("Register session\n");
204  &encapsulation_data,
205  outgoing_message);
206  break;
207 
209  OPENER_TRACE_INFO("unregister session\n");
211  &encapsulation_data, outgoing_message);
212  break;
213 
215  OPENER_TRACE_INFO("Send Request/Reply Data\n");
217  &encapsulation_data, originator_address, outgoing_message);
218  break;
219 
221  OPENER_TRACE_INFO("Send Unit Data\n");
222  return_value = HandleReceivedSendUnitDataCommand(
223  &encapsulation_data, originator_address, outgoing_message);
224  break;
225 
226  default:
227  return_value = HandleReceivedInvalidCommand(&encapsulation_data,
228  outgoing_message);
229  break;
230  }
231  }
232  }
233 
234  return return_value;
235 }
236 
237 int HandleReceivedExplictUdpData(const int socket,
238  const struct sockaddr_in *from_address,
239  const EipUint8 *buffer,
240  const size_t buffer_length,
241  int *number_of_remaining_bytes,
242  bool unicast,
243  ENIPMessage *const outgoing_message) {
244  EipStatus status = kEipStatusOk;
246  /* eat the encapsulation header*/
247  /* the structure contains a pointer to the encapsulated data*/
248  /* returns how many bytes are left after the encapsulated data*/
249  *number_of_remaining_bytes = CreateEncapsulationStructure(buffer,
250  buffer_length,
251  &encapsulation_data);
252 
253  if (kEncapsulationHeaderOptionsFlag == encapsulation_data.options) /*TODO generate appropriate error response*/
254  {
255  if (*number_of_remaining_bytes >= 0) /* check if the message is corrupt: header size + claimed payload size > than what we actually received*/
256  {
257  /* full package or more received */
258  encapsulation_data.status = kEncapsulationProtocolSuccess;
259  status = kEipStatusOkSend;
260  /* most of these functions need a reply to be send */
261  switch (encapsulation_data.command_code) {
263  OPENER_TRACE_INFO("List Service\n");
264  HandleReceivedListServicesCommand(&encapsulation_data,
265  outgoing_message);
266  break;
267 
269  OPENER_TRACE_INFO("List Identity\n");
270  if (unicast == true) {
271  HandleReceivedListIdentityCommandTcp(&encapsulation_data,
272  outgoing_message);
273  } else {
275  from_address,
276  &encapsulation_data,
277  outgoing_message);
278  status = kEipStatusOk;
279  } /* as the response has to be delayed do not send it now */
280  break;
281 
283  OPENER_TRACE_INFO("List Interfaces\n");
284  HandleReceivedListInterfacesCommand(&encapsulation_data,
285  outgoing_message);
286  break;
287 
288  /* The following commands are not to be sent via UDP */
294  default:
295  OPENER_TRACE_INFO("No command\n");
296  //TODO: Check this
297  encapsulation_data.status =
299  encapsulation_data.data_length = 0;
300  break;
301  }
302 
303  if (kEipStatusOk < status) {
304  /* if status is greater than 0 data has to be sent */
305  //status = EncapsulateData(&encapsulation_data);
306  }
307  }
308  }
309  return outgoing_message->used_message_length;
310 }
311 
312 void SkipEncapsulationHeader(ENIPMessage *const outgoing_message) {
314  &outgoing_message->current_message_position);
315 }
316 
317 void GenerateEncapsulationHeader(const EncapsulationData *const receive_data,
318  const size_t command_specific_data_length,
319  const size_t session_handle,
320  const EncapsulationProtocolErrorCode encapsulation_protocol_status,
321  ENIPMessage *const outgoing_message) {
322  outgoing_message->used_message_length += AddIntToMessage(
323  receive_data->command_code,
324  &outgoing_message->current_message_position);
325  outgoing_message->used_message_length += AddIntToMessage(
326  command_specific_data_length,
327  &outgoing_message->current_message_position);
328  outgoing_message->used_message_length += AddDintToMessage(session_handle,
329  &outgoing_message->current_message_position); //Session handle
330  outgoing_message->used_message_length += AddDintToMessage(
331  encapsulation_protocol_status,
332  &outgoing_message->current_message_position); //Status
333  memcpy(outgoing_message->current_message_position,
334  receive_data->sender_context, kSenderContextSize); // sender context
335  outgoing_message->current_message_position += kSenderContextSize;
336  outgoing_message->used_message_length += kSenderContextSize;
337  outgoing_message->used_message_length += AddDintToMessage(0,
338  &outgoing_message->current_message_position); // options
339 }
340 
346  const EncapsulationData *const receive_data,
347  ENIPMessage *const outgoing_message) {
348 
349  /* Create encapsulation header */
350  const size_t kListServicesCommandSpecificDataLength = sizeof(CipUint)
351  + sizeof(
352  g_interface_information);
353  GenerateEncapsulationHeader(receive_data,
354  kListServicesCommandSpecificDataLength,
355  0, /* Session handle will be ignored */
356  kEncapsulationProtocolSuccess, /* Protocol status */
357  outgoing_message);
358 
359  /* Command specific data copy Interface data to msg for sending */
360  outgoing_message->used_message_length += AddIntToMessage(1,
361  &outgoing_message->current_message_position); // Item count
362  outgoing_message->used_message_length += AddIntToMessage(
363  g_interface_information.type_code,
364  &outgoing_message->current_message_position);
365  outgoing_message->used_message_length += AddIntToMessage(
366  (EipUint16) (g_interface_information.length - 4),
367  &outgoing_message->current_message_position);
368  outgoing_message->used_message_length += AddIntToMessage(
369  g_interface_information.encapsulation_protocol_version,
370  &outgoing_message->current_message_position);
371  outgoing_message->used_message_length += AddIntToMessage(
372  g_interface_information.capability_flags,
373  &outgoing_message->current_message_position);
374  memcpy(outgoing_message->current_message_position,
375  g_interface_information.name_of_service,
376  sizeof(g_interface_information.name_of_service) );
377  outgoing_message->used_message_length +=
378  sizeof(g_interface_information.name_of_service);
379 }
380 
382  const EncapsulationData *const receive_data,
383  ENIPMessage *const outgoing_message) {
384 
385  /* Encapsulation header */
386  const size_t kListInterfacesCommandSpecificDataLength = sizeof(CipUint)
387  + sizeof(
388  g_interface_information);
389  GenerateEncapsulationHeader(receive_data,
390  kListInterfacesCommandSpecificDataLength,
391  0, /* Session handle will be ignored */
393  outgoing_message);
394  /* Command specific data */
395  outgoing_message->used_message_length += AddIntToMessage(0x0000,
396  &outgoing_message->current_message_position); /* Reply 0 for no information being returned */
397 }
398 
400  const EncapsulationData *const receive_data,
401  ENIPMessage *const outgoing_message) {
402  EncapsulateListIdentityResponseMessage(receive_data, outgoing_message);
403 }
404 
406  const struct sockaddr_in *const from_address,
407  const EncapsulationData *const receive_data,
408  ENIPMessage *const outgoing_message) {
409  DelayedEncapsulationMessage *delayed_message_buffer = NULL;
410 
412  i++) {
413  if (kEipInvalidSocket == g_delayed_encapsulation_messages[i].socket) {
414  delayed_message_buffer = &(g_delayed_encapsulation_messages[i]);
415  break;
416  }
417  }
418 
419  if (NULL != delayed_message_buffer) {
420  delayed_message_buffer->socket = socket;
421  memcpy( (&delayed_message_buffer->receiver), from_address,
422  sizeof(struct sockaddr_in) );
423 
425  delayed_message_buffer);
426 
427  memcpy(&(delayed_message_buffer->message[0]),
428  receive_data->communication_buffer_start,
430 
432  receive_data, outgoing_message);
433  }
434 }
435 
437  const EncapsulationData *const receive_data,
438  ENIPMessage *const outgoing_message) {
439 
440 
441  const CipUint kEncapsulationCommandListIdentityCommandSpecificLength =
442  sizeof(CipUint) + sizeof(CipInt) + sizeof(CipUint) + sizeof(CipUdint) +
443  8 *
444  sizeof(CipUsint) + sizeof(CipUint) + sizeof(CipUint) + sizeof(CipUint) + 2 *
445  sizeof(CipUsint) + sizeof(CipWord) + sizeof(CipUdint) +
446  sizeof(
447  CipUsint) + product_name_.length + sizeof(CipUsint);
448  const CipUint kEncapsulationCommandListIdentityLength =
449  kEncapsulationCommandListIdentityCommandSpecificLength + sizeof(CipUint) +
450  sizeof(CipUint)
451  + sizeof(CipUint); /* Last element is item count */
452 
453  GenerateEncapsulationHeader(receive_data,
454  kEncapsulationCommandListIdentityLength,
455  0, /* Session handle will be ignored by receiver */
457  outgoing_message);
458 
459  outgoing_message->used_message_length += AddIntToMessage(1,
460  &outgoing_message->current_message_position); /* Item count: one item */
461 
462  /* Item ID*/
463  const CipUint kItemIDCipIdentity = 0x0C;
464  outgoing_message->used_message_length += AddIntToMessage(
465  kItemIDCipIdentity,
466  &outgoing_message->current_message_position);
467 
468  outgoing_message->used_message_length += AddIntToMessage(
469  kEncapsulationCommandListIdentityCommandSpecificLength,
470  &outgoing_message->current_message_position);
471 
472  outgoing_message->used_message_length += AddIntToMessage(
474  &outgoing_message->current_message_position);
475 
476  outgoing_message->used_message_length += EncapsulateIpAddress(
477  htons(kOpenerEthernetPort), interface_configuration_.ip_address,
478  &outgoing_message->current_message_position);
479 
481  memset(outgoing_message->current_message_position, 0, 8);
482  outgoing_message->used_message_length += MoveMessageNOctets(8,
483  (const CipOctet **) &outgoing_message->current_message_position);
484 
485  outgoing_message->used_message_length += AddIntToMessage(vendor_id_,
486  &outgoing_message->current_message_position);
487  outgoing_message->used_message_length += AddIntToMessage(device_type_,
488  &outgoing_message->current_message_position);
490  &outgoing_message->current_message_position);
491  *(outgoing_message->current_message_position)++ = revision_.major_revision;
492  outgoing_message->used_message_length++;
493  *(outgoing_message->current_message_position)++ = revision_.minor_revision;
494  outgoing_message->used_message_length++;
495  outgoing_message->used_message_length += AddIntToMessage(status_,
496  &outgoing_message->current_message_position);
498  &outgoing_message->current_message_position);
499  *outgoing_message->current_message_position++ =
500  (unsigned char) product_name_.length;
501  outgoing_message->used_message_length++;
502 
503  memcpy(outgoing_message->current_message_position, product_name_.string,
504  product_name_.length);
505  outgoing_message->current_message_position += product_name_.length;
506  outgoing_message->used_message_length += product_name_.length;
507 
508  *outgoing_message->current_message_position++ = 0xFF;
509  outgoing_message->used_message_length++;
510 
511 }
512 
513 void DetermineDelayTime(const EipByte *const buffer_start,
514  DelayedEncapsulationMessage *const delayed_message_buffer)
515 {
516 
517  MoveMessageNOctets(12, (const CipOctet **) &buffer_start); /* start of the sender context */
518  EipUint16 maximum_delay_time = GetIntFromMessage(
519  (const EipUint8 **const ) &buffer_start);
520 
521  if (0 == maximum_delay_time) {
522  maximum_delay_time = kListIdentityDefaultDelayTime;
523  } else if (kListIdentityMinimumDelayTime > maximum_delay_time) { /* if maximum_delay_time is between 1 and 500ms set it to 500ms */
524  maximum_delay_time = kListIdentityMinimumDelayTime;
525  }
526  delayed_message_buffer->time_out = (maximum_delay_time * rand() ) / RAND_MAX; /* Sets delay time between 0 and maximum_delay_time */
527 }
528 
530  const EncapsulationData *const receive_data,
531  const size_t session_handle,
532  const EncapsulationProtocolErrorCode encapsulation_protocol_status,
533  ENIPMessage *const outgoing_message) {
534 
535  /* Encapsulation header */
536  const size_t kListInterfacesCommandSpecificDataLength = sizeof(CipUint)
537  + sizeof(CipUint);
538  assert(kListInterfacesCommandSpecificDataLength == 4);
539  GenerateEncapsulationHeader(receive_data,
540  kListInterfacesCommandSpecificDataLength,
541  session_handle,
542  encapsulation_protocol_status,
543  outgoing_message);
544 
545  outgoing_message->used_message_length += AddIntToMessage(1,
546  &outgoing_message->current_message_position); /* protocol version*/
547  outgoing_message->used_message_length += AddIntToMessage(
548  0,
549  &outgoing_message->current_message_position); /* Options flag, shall be set to zero */
550 }
551 
552 /* @brief Check supported protocol, generate session handle, send replay back to originator.
553  * @param socket Socket this request is associated to. Needed for double register check
554  * @param receive_data Pointer to received data with request/response.
555  */
557  const EncapsulationData *const receive_data,
558  ENIPMessage *const outgoing_message) {
559  int session_index = 0;
560  size_t session_handle = 0;
561  EncapsulationProtocolErrorCode encapsulation_protocol_status =
563 
564  EipUint16 protocol_version =
566  (const EipUint8 **const ) &receive_data->current_communication_buffer_position);
567  EipUint16 option_flag =
569  (const EipUint8 **const ) &receive_data->current_communication_buffer_position);
570 
571  /* check if requested protocol version is supported and the register session option flag is zero*/
572  if ( (0 < protocol_version)
573  && (protocol_version <= kSupportedProtocolVersion)
574  && (0 == option_flag) ) { /*Option field should be zero*/
575  /* check if the socket has already a session open */
576  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
577  if (g_registered_sessions[i] == socket) {
578  /* the socket has already registered a session this is not allowed*/
580  "Error: A session is already registered at socket %d\n",
581  socket);
582  session_handle = i + 1; /*return the already assigned session back, the cip spec is not clear about this needs to be tested*/
583  encapsulation_protocol_status = kEncapsulationProtocolInvalidCommand;
584  session_index = kSessionStatusInvalid;
585  break;
586  }
587  }
588 
589  if (kSessionStatusInvalid != session_index) {
590  session_index = GetFreeSessionIndex();
591  if (kSessionStatusInvalid == session_index) /* no more sessions available */
592  {
593  encapsulation_protocol_status =
595  } else { /* successful session registered */
597  g_timestamps,
598  OPENER_NUMBER_OF_SUPPORTED_SESSIONS);
599  SocketTimerSetSocket(socket_timer, socket);
601  g_registered_sessions[session_index] = socket; /* store associated socket */
602  session_handle = session_index + 1;
603  encapsulation_protocol_status = kEncapsulationProtocolSuccess;
604  }
605  }
606  } else { /* protocol not supported */
607  encapsulation_protocol_status = kEncapsulationProtocolUnsupportedProtocol;
608  }
609 
611  session_handle,
612  encapsulation_protocol_status,
613  outgoing_message);
614 
615 }
616 
617 /* TODO: Update and doxyfy
618  * INT8 UnregisterSession(struct S_Encapsulation_Data *pa_S_ReceiveData)
619  * close all corresponding TCP connections and delete session handle.
620  * pa_S_ReceiveData pointer to unregister session request with corresponding socket handle.
621  */
623  const EncapsulationData *const receive_data,
624  ENIPMessage *const outgoing_message) {
625  OPENER_TRACE_INFO("encap.c: Unregister Session Command\n");
626  if ( (0 < receive_data->session_handle) && (receive_data->session_handle <=
628  {
629  size_t i = receive_data->session_handle - 1;
630  if (kEipInvalidSocket != g_registered_sessions[i]) {
632  g_registered_sessions[i] = kEipInvalidSocket;
634  return kEipStatusOk;
635  }
636  }
637 
638  /* no such session registered */
639  GenerateEncapsulationHeader(receive_data,
640  0,
641  receive_data->session_handle,
643  outgoing_message);
644  return kEipStatusOkSend;
645 }
646 
653  const EncapsulationData *const receive_data,
654  const struct sockaddr *const originator_address,
655  ENIPMessage *const outgoing_message) {
656  EipStatus return_value = kEipStatusOkSend;
657 
658  if (receive_data->data_length >= 6) {
659  /* Command specific data UDINT .. Interface Handle, UINT .. Timeout, CPF packets */
660  /* don't use the data yet */
662  (const EipUint8 **const ) &receive_data->current_communication_buffer_position); /* skip over null interface handle*/
664  (const EipUint8 **const ) &receive_data->current_communication_buffer_position); /* skip over unused timeout value*/
665  ( (EncapsulationData *const)receive_data )->data_length -= 6; /* the rest is in CPF format*/
666 
667  if (kSessionStatusValid == CheckRegisteredSessions(receive_data) ) /* see if the EIP session is registered*/
668  {
669  EipInt16 send_size =
671  originator_address,
672  outgoing_message);
673 
674  return_value = send_size;
675 
676  if (send_size < 0) { /* need to send reply */
677  return_value = kEipStatusError;
678  }
679  } else { /* received a package with non registered session handle */
680  InitializeENIPMessage(outgoing_message);
681  GenerateEncapsulationHeader(receive_data,
682  0,
683  receive_data->session_handle,
685  outgoing_message);
686  }
687  }
688  return return_value;
689 }
690 
699  const EncapsulationData *const receive_data,
700  const struct sockaddr *const originator_address,
701  ENIPMessage *const outgoing_message) {
702  EipStatus return_value = kEipStatusOkSend;
703 
704  if (receive_data->data_length >= 6) {
705  /* Command specific data UDINT .. Interface Handle, UINT .. Timeout, CPF packets */
706  /* don't use the data yet */
708  (const EipUint8 **const ) &receive_data->current_communication_buffer_position); /* skip over null interface handle*/
710  (const EipUint8 **const ) &receive_data->current_communication_buffer_position); /* skip over unused timeout value*/
711  ( (EncapsulationData *const)receive_data )->data_length -= 6; /* the rest is in CPF format*/
712 
713  if (kSessionStatusValid == CheckRegisteredSessions(receive_data) ) /* see if the EIP session is registered*/
714  {
715  EipInt16 send_size =
716  NotifyCommonPacketFormat(receive_data,
717  originator_address,
718  outgoing_message);
719  return_value = send_size;
720 
721  if (send_size < 0) { /* need to send reply */
722  return_value = kEipStatusError;
723  }
724  } else { /* received a package with non registered session handle */
725  InitializeENIPMessage(outgoing_message);
726  GenerateEncapsulationHeader(receive_data,
727  0,
728  receive_data->session_handle,
730  outgoing_message);
731  }
732  }
733  return return_value;
734 }
735 
737  const EncapsulationData *const receive_data,
738  ENIPMessage *const outgoing_message) {
739 
740  /* Encapsulation header */
741  GenerateEncapsulationHeader(receive_data,
742  0,
743  receive_data->session_handle,
745  outgoing_message);
746  return outgoing_message->used_message_length;
747 
748 }
749 
755  for (size_t session_index = 0;
756  session_index < OPENER_NUMBER_OF_SUPPORTED_SESSIONS;
757  session_index++) {
758  if (kEipInvalidSocket == g_registered_sessions[session_index]) {
759  return session_index;
760  }
761  }
762  return kSessionStatusInvalid;
763 }
764 
775  int receive_buffer_length,
777 {
778  encapsulation_data->communication_buffer_start =
779  (EipUint8 *) receive_buffer;
780  encapsulation_data->command_code = GetIntFromMessage(&receive_buffer);
781  encapsulation_data->data_length = GetIntFromMessage(&receive_buffer);
782  encapsulation_data->session_handle = GetDintFromMessage(&receive_buffer);
783  encapsulation_data->status = GetDintFromMessage(&receive_buffer);
784 
785  memcpy(encapsulation_data->sender_context, receive_buffer,
787  receive_buffer += kSenderContextSize;
788  encapsulation_data->options = GetDintFromMessage(&receive_buffer);
789  encapsulation_data->current_communication_buffer_position =
790  (EipUint8 *) receive_buffer;
791  return (receive_buffer_length - ENCAPSULATION_HEADER_LENGTH
792  - encapsulation_data->data_length);
793 }
794 
801  const EncapsulationData *const receive_data) {
802  if ( (0 < receive_data->session_handle) && (receive_data->session_handle <=
804  {
805  if (kEipInvalidSocket
806  != g_registered_sessions[receive_data->session_handle - 1]) {
807  return kSessionStatusValid;
808  }
809  }
810  return kSessionStatusInvalid;
811 }
812 
814  const CipConnectionObject *const connection_object) {
815  OPENER_TRACE_INFO("encap.c: Close session by handle\n");
816  size_t session_handle = connection_object->associated_encapsulation_session;
817  CloseTcpSocket(g_registered_sessions[session_handle - 1]);
818  g_registered_sessions[session_handle - 1] = kEipInvalidSocket;
819  OPENER_TRACE_INFO("encap.c: Close session by handle done\n");
820 }
821 
822 void CloseSession(int socket) {
823  OPENER_TRACE_INFO("encap.c: Close session\n");
824  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
825  if (g_registered_sessions[i] == socket) {
826  CloseTcpSocket(socket);
827  g_registered_sessions[i] = kEipInvalidSocket;
829  break;
830  }
831  }
832  OPENER_TRACE_INFO("encap.c: Close session done\n");
833 }
834 
835 void RemoveSession(const int socket) {
836  OPENER_TRACE_INFO("encap.c: Removing session\n");
837  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
838  if (g_registered_sessions[i] == socket) {
839  g_registered_sessions[i] = kEipInvalidSocket;
841  break;
842  }
843  }
844  OPENER_TRACE_INFO("encap.c: Session removed\n");
845 }
846 
848  OPENER_TRACE_INFO("encap.c: Encapsulation shutdown\n");
849  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
850  if (kEipInvalidSocket != g_registered_sessions[i]) {
852  g_registered_sessions[i] = kEipInvalidSocket;
853  }
854  }
855 }
856 
857 void ManageEncapsulationMessages(const MilliSeconds elapsed_time) {
859  i++) {
860  if (kEipInvalidSocket != g_delayed_encapsulation_messages[i].socket) {
861  g_delayed_encapsulation_messages[i].time_out -= elapsed_time;
862  if (0 >= g_delayed_encapsulation_messages[i].time_out) {
863  /* If delay is reached or passed, send the UDP message */
864  SendUdpData(&(g_delayed_encapsulation_messages[i].receiver),
865  g_delayed_encapsulation_messages[i].socket,
866  &(g_delayed_encapsulation_messages[i].message[0]),
867  g_delayed_encapsulation_messages[i].message_size);
868  g_delayed_encapsulation_messages[i].socket = kEipInvalidSocket;
869  }
870  }
871  }
872 }
873 
875  const CipConnectionObject *const connection_object) {
876  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
877  if (kEipInvalidSocket != g_registered_sessions[i]) {
878  struct sockaddr_in encapsulation_session_addr = { 0 };
879  socklen_t addrlength = sizeof(encapsulation_session_addr);
880  if (getpeername(g_registered_sessions[i],
881  &encapsulation_session_addr, &addrlength) < 0) { /* got error */
882  int error_code = GetSocketErrorNumber();
883  char *error_message = GetErrorMessage(error_code);
885  "encap.c: error on getting peer name on closing session: %d - %s\n",
886  error_code, error_message);
887  FreeErrorMessage(error_message);
888  }
889  if (encapsulation_session_addr.sin_addr.s_addr
890  == connection_object->originator_address.sin_addr.s_addr) {
892  }
893  }
894  }
895 }
896 
897 size_t GetSessionFromSocket(const int socket_handle) {
898  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
899  if (socket_handle == g_registered_sessions[i]) {
900  return i;
901  }
902  }
904 }
905 
906 void CloseClass3ConnectionBasedOnSession(size_t encapsulation_session_handle) {
908  while (NULL != node) {
909  CipConnectionObject *connection_object = node->data;
912  connection_object)
913  && connection_object->associated_encapsulation_session
914  == encapsulation_session_handle) {
915  connection_object->connection_close_function(connection_object);
916  }
917  node = node->next;
918  }
919 }
CIP Short String.
Definition: ciptypes.h:130
CipUdint options
Definition: encap.h:47
#define OPENER_NUMBER_OF_SUPPORTED_SESSIONS
Number of sessions that can be handled at the same time.
Tracing infrastructure for OpENer.
MilliSeconds g_actual_time
void CloseSession(int socket)
Inform the encapsulation layer that the remote host has closed the connection.
Definition: encap.c:822
EipStatus SendUdpData(struct sockaddr_in *socket_data, int socket_handle, EipUint8 *data, EipUint16 data_length)
Create a producing or consuming UDP socket.
Data structure to store last usage times for sockets.
Definition: socket_timer.h:15
char * GetErrorMessage(int error_number)
Returns a human readable message for the given error number.
Definition: opener_error.c:21
void EncapsulateListIdentityResponseMessage(const EncapsulationData *const receive_data, ENIPMessage *const outgoing_message)
Definition: encap.c:436
Delayed Encapsulation Message structure.
Definition: encap.c:76
DoublyLinkedListNode * first
This file includes the prototypes for error resolution functions like strerror_r or WSAGetLastError...
void CloseEncapsulationSessionBySockAddr(const CipConnectionObject *const connection_object)
Definition: encap.c:874
const EipUint8 * current_communication_buffer_position
Definition: encap.h:49
int HandleReceivedExplictUdpData(const int socket, const struct sockaddr_in *from_address, const EipUint8 *buffer, const size_t buffer_length, int *number_of_remaining_bytes, bool unicast, ENIPMessage *const outgoing_message)
Notify the encapsulation layer that an explicit message has been received via UDP.
Definition: encap.c:237
void HandleReceivedListServicesCommand(const EncapsulationData *const receive_data, ENIPMessage *const outgoing_message)
generate reply with "Communications Services" + compatibility Flags.
Definition: encap.c:345
const int kSenderContextSize
Definition: encap.c:49
const int kListIdentityDefaultDelayTime
Definition: encap.c:42
void HandleReceivedListInterfacesCommand(const EncapsulationData *const receive_data, ENIPMessage *const outgoing_message)
Definition: encap.c:381
EipStatus HandleReceivedUnregisterSessionCommand(const EncapsulationData *const receive_data, ENIPMessage *const outgoing_message)
Definition: encap.c:622
EipUint32 GetDintFromMessage(const EipUint8 **const buffer)
Reads EIP_UINT32 from *buffer and converts little endian to host.
Definition: endianconv.c:83
CipOctet * current_message_position
Definition: enipmessage.h:13
Responsible for Endianess conversion.
#define OPENER_TRACE_ERR(...)
Definition: trace.h:86
EipByte message[ENCAP_MAX_DELAYED_ENCAP_MESSAGE_SIZE]
Definition: encap.c:80
SocketTimer g_timestamps[OPENER_NUMBER_OF_SUPPORTED_SESSIONS]
void InitializeENIPMessage(ENIPMessage *const message)
Definition: enipmessage.c:10
void GenerateEncapsulationHeader(const EncapsulationData *const receive_data, const size_t command_specific_data_length, const size_t session_handle, const EncapsulationProtocolErrorCode encapsulation_protocol_status, ENIPMessage *const outgoing_message)
Definition: encap.c:317
CipUdint serial_number_
Definition: cipidentity.c:47
void ManageEncapsulationMessages(const MilliSeconds elapsed_time)
Handle delayed encapsulation message responses.
Definition: encap.c:857
const int kListIdentityMinimumDelayTime
Definition: encap.c:43
CipShortString product_name_
Definition: cipidentity.c:48
void EncapsulateRegisterSessionCommandResponseMessage(const EncapsulationData *const receive_data, const size_t session_handle, const EncapsulationProtocolErrorCode encapsulation_protocol_status, ENIPMessage *const outgoing_message)
Definition: encap.c:529
int16_t CipInt
Definition: typedefs.h:50
EncapsulationCommand
definition of known encapsulation commands
Definition: encap.c:52
EipStatus HandleReceivedSendUnitDataCommand(const EncapsulationData *const receive_data, const struct sockaddr *const originator_address, ENIPMessage *const outgoing_message)
Call Connection Manager.
Definition: encap.c:652
CipUint product_code_
Definition: cipidentity.c:43
int32_t EipInt32
Definition: typedefs.h:31
EncapsulationProtocolErrorCode
definition of status codes in encapsulation protocol All other codes are either legacy codes...
Definition: encap.h:30
DelayedEncapsulationMessage g_delayed_encapsulation_messages[ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES]
Definition: encap.c:89
ConnectionCloseFunction connection_close_function
void DetermineDelayTime(const EipByte *const buffer_start, DelayedEncapsulationMessage *const delayed_message_buffer)
Definition: encap.c:513
EipUint16 encapsulation_protocol_version
Definition: encap.h:55
void HandleReceivedListIdentityCommandTcp(const EncapsulationData *const receive_data, ENIPMessage *const outgoing_message)
Definition: encap.c:399
SessionStatus
Definition: encap.c:45
uint8_t CipOctet
Data types as defined in the CIP Specification Vol 1 Appendix C.
Definition: typedefs.h:41
DoublyLinkedListNode * next
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
void CloseClass3ConnectionBasedOnSession(size_t encapsulation_session_handle)
Definition: encap.c:906
EipStatus
EIP stack status enum.
Definition: typedefs.h:93
uint8_t EipUint8
Definition: typedefs.h:32
void CloseSessionBySessionHandle(const CipConnectionObject *const connection_object)
Definition: encap.c:813
EipStatus HandleReceivedInvalidCommand(const EncapsulationData *const receive_data, ENIPMessage *const outgoing_message)
Definition: encap.c:736
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
void HandleReceivedListIdentityCommandUdp(const int socket, const struct sockaddr_in *const from_address, const EncapsulationData *const receive_data, ENIPMessage *const outgoing_message)
Definition: encap.c:405
#define OPENER_TRACE_INFO(...)
Definition: trace.h:89
void SkipEncapsulationHeader(ENIPMessage *const outgoing_message)
Definition: encap.c:312
int MoveMessageNOctets(const int amount_of_bytes_moved, const CipOctet **message_runner)
Definition: endianconv.c:258
CipUint vendor_id_
Definition: cipidentity.c:41
void EncapsulationShutDown(void)
Shutdown the encapsulation layer.
Definition: encap.c:847
int NotifyConnectedCommonPacketFormat(const EncapsulationData *const received_data, const struct sockaddr *const originator_address, ENIPMessage *const outgoing_message)
Definition: cpf.c:91
unsigned long socklen_t
CipOctet sender_context[8]
Definition: encap.h:46
const int kEncapsulationHeaderSessionHandlePosition
Definition: encap.c:40
#define ENCAPSULATION_HEADER_LENGTH
Definition: encap.h:22
SocketTimer * SocketTimerArrayGetEmptySocketTimer(SocketTimer *const array_of_socket_timers, const size_t array_length)
Get an empty Socket Timer entry.
Definition: socket_timer.c:53
uint8_t CipUsint
Definition: typedefs.h:46
SessionStatus CheckRegisteredSessions(const EncapsulationData *const receive_data)
Check if received package belongs to registered session.
Definition: encap.c:800
CipUdint session_handle
Definition: encap.h:44
void RemoveSession(const int socket)
Definition: encap.c:835
#define ENCAP_MAX_DELAYED_ENCAP_MESSAGE_SIZE
Definition: encap.c:70
const int kSupportedProtocolVersion
Definition: encap.c:36
Struct for saving TCP/IP interface information.
Definition: ciptypes.h:294
EncapsulationInterfaceInformation g_interface_information
Definition: encap.c:84
DoublyLinkedList connection_list
CipUint device_type_
Definition: cipidentity.c:42
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
EipStatus HandleReceivedSendRequestResponseDataCommand(const EncapsulationData *const receive_data, const struct sockaddr *const originator_address, ENIPMessage *const outgoing_message)
Call UCMM or Message Router if UCMM not implemented.
Definition: encap.c:698
int g_registered_sessions[OPENER_NUMBER_OF_SUPPORTED_SESSIONS]
Definition: encap.c:86
void EncapsulationInit(void)
Initialize the encapsulation layer.
Definition: encap.c:123
CipUdint status
Definition: encap.h:45
CipUint data_length
Definition: encap.h:43
int16_t EipInt16
Definition: typedefs.h:30
struct sockaddr_in receiver
Definition: encap.c:79
This file contains the public interface of the encapsulation layer.
unsigned long MilliSeconds
Definition: typedefs.h:68
CapabilityFlags
definition of capability flags
Definition: encap.c:64
EipInt16 CreateEncapsulationStructure(const EipUint8 *receive_buffer, int receive_buffer_length, EncapsulationData *const encapsulation_data)
copy data from pa_buf in little endian to host in structure.
Definition: encap.c:774
void HandleReceivedRegisterSessionCommand(int socket, const EncapsulationData *const receive_data, ENIPMessage *const outgoing_message)
Definition: encap.c:556
#define ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES
Definition: encap.c:68
size_t GetSessionFromSocket(const int socket_handle)
Definition: encap.c:897
const EipUint8 * communication_buffer_start
Definition: encap.h:48
uint32_t CipUdint
Definition: typedefs.h:48
uint16_t CipUint
Definition: typedefs.h:47
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
void FreeErrorMessage(char *error_message)
Frees the space of the error message generated by GetErrorMessage(int)
Definition: opener_error.c:34
size_t used_message_length
Definition: enipmessage.h:14
const int kEncapsulationHeaderOptionsFlag
Definition: encap.c:38
CipRevision revision_
Definition: cipidentity.c:44
int EncapsulateIpAddress(EipUint16 port, EipUint32 address, EipByte **communication_buffer)
Encapsulate the sockaddr information as necessary for the Common Packet Format data items...
Definition: endianconv.c:197
CipUint command_code
Definition: encap.h:42
void DetermineEndianess()
Detects Endianess of the platform and sets global g_nOpENerPlatformEndianess variable accordingly...
Definition: endianconv.c:239
EipUint8 length
Definition: ciptypes.h:131
EipByte * string
Definition: ciptypes.h:132
void SocketTimerSetSocket(SocketTimer *const socket_timer, const int socket)
Sets socket of a Socket Timer.
Definition: socket_timer.c:11
uint16_t CipWord
Definition: typedefs.h:44
uint16_t EipUint16
Definition: typedefs.h:33
CipTcpIpNetworkInterfaceConfiguration interface_configuration_
struct sockaddr_in originator_address
int GetSocketErrorNumber()
Gets the error number or equivalent.
Definition: opener_error.c:17
void SocketTimerSetLastUpdate(SocketTimer *const socket_timer, const MilliSeconds actual_time)
Sets time stamp entry of the Socket Timer.
Definition: socket_timer.c:17
int HandleReceivedExplictTcpData(int socket, EipUint8 *buffer, size_t length, int *remaining_bytes, struct sockaddr *originator_address, ENIPMessage *const outgoing_message)
Notify the encapsulation layer that an explicit message has been received via TCP.
Definition: encap.c:153
int GetFreeSessionIndex(void)
search for available sessions an return index.
Definition: encap.c:754
int NotifyCommonPacketFormat(EncapsulationData *const received_data, const struct sockaddr *const originator_address, ENIPMessage *const outgoing_message)
Definition: cpf.c:26
CipWord status_
Definition: cipidentity.c:46
void CloseTcpSocket(int socket_handle)
ConnectionObjectTransportClassTriggerTransportClass ConnectionObjectGetTransportClassTriggerTransportClass(const CipConnectionObject *const connection_object)