OpENer - Open Source EtherNet/IP(TM) I/O Target Stack  2.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ciptcpipinterface.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 
8 #include "ciptcpipinterface.h"
9 
10 #include "opener_user_conf.h"
11 #include "cipcommon.h"
12 #include "cipmessagerouter.h"
13 #include "ciperror.h"
14 #include "endianconv.h"
15 #include "cipethernetlink.h"
16 #include "opener_api.h"
17 #include "trace.h"
18 #include "cipassembly.h"
19 
24 { 2,
26  1,
27  0
28 };
29 
31 { 0, /* default IP address */
32  0, /* NetworkMask */
33  0, /* Gateway */
34  0, /* NameServer */
35  0, /* NameServer2 */
36  { /* DomainName */
37  0, NULL,
38  } };
39 
41 { 0, NULL };
47 
53 MulticastAddressConfiguration g_multicast_configuration = { 0, /* us the default allocation algorithm */
54  0, /* reserved */
55  1, /* we currently use only one multicast address */
56  0 /* the multicast address will be allocated on ip address configuration */
57 };
58 
64 
65 /************** Functions ****************************************/
67  CipInstance *instance,
68  CipMessageRouterRequest *message_router_request,
69  CipMessageRouterResponse *message_router_response,
70  struct sockaddr *originator_address,
71  const int encapsulation_session);
72 
74  CipInstance *instance,
75  CipMessageRouterRequest *message_router_request,
76  CipMessageRouterResponse *message_router_response,
77  struct sockaddr *originator_address,
78  const int encapsulation_session);
79 
81  CipInstance *instance,
82  CipMessageRouterRequest *message_router_request,
83  CipMessageRouterResponse *message_router_response,
84  struct sockaddr *originator_address,
85  const int encapsulation_session) {
87  instance, message_router_request->request_path.attribute_number);
88  (void) instance; /*Suppress compiler warning */
89  EipUint16 attribute_number = message_router_request->request_path
91 
92  if (NULL != attribute) {
93  uint8_t set_bit_mask = (instance->cip_class->set_bit_mask[CalculateIndex(
94  attribute_number)
95  ]);
96  if ( set_bit_mask & ( 1 << ( (attribute_number) % 8 ) ) ) {
97  switch (attribute_number) {
98  case 3: {
99  CipUint configuration_control_recieved = GetDintFromMessage(
100  &(message_router_request->data) );
101  if ( (configuration_control_recieved >= 0x03)
102  && (configuration_control_recieved <= 0x0F) ) {
103  message_router_response->general_status =
105 
106  } else {
107 
108  OPENER_TRACE_INFO(" setAttribute %d\n", attribute_number);
109 
110  if (attribute->data != NULL) {
111  CipDword *data = (CipDword *) attribute->data;
112  *(data) = configuration_control_recieved;
113  message_router_response->general_status = kCipErrorSuccess;
114  } else {
115  message_router_response->general_status = kCipErrorNotEnoughData;
116  }
117  }
118  }
119  break;
120 
121  case 13: {
122 
123  CipUint inactivity_timeout_received = GetIntFromMessage(
124  &(message_router_request->data) );
125 
126  if (inactivity_timeout_received > 3600) {
127  message_router_response->general_status =
129  } else {
130 
131  OPENER_TRACE_INFO("setAttribute %d\n", attribute_number);
132 
133  if (attribute->data != NULL) {
134 
135  CipUint *data = (CipUint *) attribute->data;
136  *(data) = inactivity_timeout_received;
137  message_router_response->general_status = kCipErrorSuccess;
138  } else {
139  message_router_response->general_status = kCipErrorNotEnoughData;
140  }
141  }
142  }
143  break;
144 
145  default:
146  message_router_response->general_status =
148  break;
149  }
150  } else {
151  message_router_response->general_status = kCipErrorAttributeNotSetable;
152  }
153  } else {
154  /* we don't have this attribute */
155  message_router_response->general_status = kCipErrorAttributeNotSupported;
156  }
157 
158  message_router_response->size_of_additional_status = 0;
159  message_router_response->data_length = 0;
160  message_router_response->reply_service = (0x80
161  | message_router_request->service);
162  return kEipStatusOkSend;
163 }
164 
166  CipClass *tcp_ip_class = NULL;
167 
168  if ( ( tcp_ip_class = CreateCipClass(kCipTcpIpInterfaceClassCode, 0, /* # class attributes*/
169  7, /* # highest class attribute number*/
170  2, /* # class services*/
171  9, /* # instance attributes*/
172  13, /* # highest instance attribute number*/
173  3, /* # instance services*/
174  1, /* # instances*/
175  "TCP/IP interface", 4, /* # class revision*/
176  NULL /* # function pointer for initialization*/
177  ) ) == 0 ) {
178  return kEipStatusError;
179  }
180 
181  CipInstance *instance = GetCipInstance(tcp_ip_class, 1); /* bind attributes to the instance #1 that was created above*/
182 
183  InsertAttribute(instance, 1, kCipDword, (void *) &tcp_status_,
185  InsertAttribute(instance, 2, kCipDword, (void *) &configuration_capability_,
187  InsertAttribute(instance, 3, kCipDword, (void *) &configuration_control_,
189  InsertAttribute(instance, 4, kCipEpath, &physical_link_object_,
192  &interface_configuration_, kGetableSingleAndAll);
193  InsertAttribute(instance, 6, kCipString, (void *) &hostname_,
195 
196  InsertAttribute(instance, 8, kCipUsint, (void *) &g_time_to_live_value,
198  InsertAttribute(instance, 9, kCipAny, (void *) &g_multicast_configuration,
200  InsertAttribute(instance, 13, kCipUint,
202 
203  InsertService(tcp_ip_class, kGetAttributeSingle,
205  "GetAttributeSingleTCPIPInterface");
206 
208  "GetAttributeAllTCPIPInterface");
209 
211  "SetAttributeSingle");
212  return kEipStatusOk;
213 }
214 
216  /*Only free the resources if they are initialized */
217  if (NULL != hostname_.string) {
218  CipFree(hostname_.string);
219  hostname_.string = NULL;
220  }
221 
222  if (NULL != interface_configuration_.domain_name.string) {
223  CipFree(interface_configuration_.domain_name.string);
224  interface_configuration_.domain_name.string = NULL;
225  }
226 }
227 
229  CipInstance *const RESTRICT instance,
230  CipMessageRouterRequest *RESTRICT const message_router_request,
231  CipMessageRouterResponse *RESTRICT const message_router_response,
232  struct sockaddr *originator_address,
233  const int encapsulation_session) {
234 
235  EipByte *message = message_router_response->data;
236 
237  message_router_response->data_length = 0;
238  message_router_response->reply_service = (0x80
239  | message_router_request->service);
240  message_router_response->size_of_additional_status = 0;
241 
242  EipUint16 attribute_number = message_router_request->request_path
243  .attribute_number;
244  uint8_t get_bit_mask = 0;
245 
246  message_router_response->general_status = kCipErrorAttributeNotSupported;
247 
248  if (9 == message_router_request->request_path.attribute_number) { /* attribute 9 can not be easily handled with the default mechanism therefore we will do it by hand */
249  if (kGetAttributeAll == message_router_request->service) {
250  get_bit_mask = (instance->cip_class->get_all_bit_mask[CalculateIndex(
251  attribute_number)]);
252  message_router_response->general_status = kCipErrorSuccess;
253  } else {
254  get_bit_mask = (instance->cip_class->get_single_bit_mask[CalculateIndex(
255  attribute_number)
256  ]);
257  }
258 
259  if ( 0 == ( get_bit_mask & ( 1 << (attribute_number % 8) ) ) ) {
260  return kEipStatusOkSend;
261  }
262  message_router_response->general_status = kCipErrorSuccess;
263 
264  message_router_response->data_length += EncodeData(
265  kCipUsint, &(g_multicast_configuration.alloc_control), &message);
266  message_router_response->data_length += EncodeData(
267  kCipUsint, &(g_multicast_configuration.reserved_shall_be_zero),
268  &message);
269  message_router_response->data_length += EncodeData(
270  kCipUint,
271  &(g_multicast_configuration.number_of_allocated_multicast_addresses),
272  &message);
273 
274  EipUint32 multicast_address = ntohl(
275  g_multicast_configuration.starting_multicast_address);
276 
277  message_router_response->data_length += EncodeData(kCipUdint,
278  &multicast_address,
279  &message);
280  } else {
281  CipAttributeStruct *attribute = GetCipAttribute(instance, attribute_number);
282 
283  if ( (NULL != attribute) && ( NULL != attribute->data) ) {
284 
285  OPENER_TRACE_INFO("getAttribute %d\n",
286  message_router_request->request_path.attribute_number); /* create a reply message containing the data*/
287 
288  if (kGetAttributeAll == message_router_request->service) {
289  get_bit_mask = (instance->cip_class->get_all_bit_mask[CalculateIndex(
290  attribute_number)
291  ]);
292  message_router_response->general_status = kCipErrorSuccess;
293  } else {
294  get_bit_mask = (instance->cip_class->get_single_bit_mask[CalculateIndex(
295  attribute_number)
296  ]);
297  }
298 
299  if ( 0 == ( get_bit_mask & ( 1 << ( (attribute_number) % 8 ) ) ) ) {
300  return kEipStatusOkSend;
301  }
302 
303  /*TODO think if it is better to put this code in an own
304  * getAssemblyAttributeSingle functions which will call get attribute
305  * single.
306  */
307 
308  if (attribute->type == kCipByteArray
309  && instance->cip_class->class_id == kCipAssemblyClassCode) {
310  /* we are getting a byte array of a assembly object, kick out to the app callback */
311  OPENER_TRACE_INFO(" -> getAttributeSingle CIP_BYTE_ARRAY\r\n");
312  BeforeAssemblyDataSend(instance);
313  }
314 
315  message_router_response->data_length = EncodeData(attribute->type,
316  attribute->data,
317  &message);
318  message_router_response->general_status = kCipErrorSuccess;
319  }
320  }
321 
322  return kEipStatusOkSend;
323 }
324 
326  CipInstance *instance,
327  CipMessageRouterRequest *message_router_request,
328  CipMessageRouterResponse *message_router_response,
329  struct sockaddr *originator_address,
330  const int encapsulation_session) {
331 
332  EipUint8 *response = message_router_response->data; /* pointer into the reply */
333  CipAttributeStruct *attribute = instance->attributes;
334 
335  for (int j = 0; j < instance->cip_class->number_of_attributes; j++) /* for each instance attribute of this class */
336  {
337  int attribute_number = attribute->attribute_number;
338  if (attribute_number < 32) /* only return attributes that are flagged as being part of GetAttributeALl */
339  {
340  message_router_request->request_path.attribute_number = attribute_number;
341 
342  if (8 == attribute_number) { /* insert 6 zeros for the required empty safety network number according to Table 5-3.10 */
343  memset(message_router_response->data, 0, 6);
344  message_router_response->data += 6;
345  }
346 
347  if ( kEipStatusOkSend
348  != GetAttributeSingleTcpIpInterface(instance, message_router_request,
349  message_router_response,
350  originator_address,
351  encapsulation_session) ) {
352  message_router_response->data = response;
353  return kEipStatusError;
354  }
355  message_router_response->data += message_router_response->data_length;
356 
357  if (9 == attribute_number) {
358  /* returning default value for unimplemented attributes 10,11 and 12 */
359 
360  /* attribute 10, type: BOOL, default value: 0 */
361  message_router_response->data += 6;
362  *(message_router_response->data) = 0;
363  message_router_response->data += 1;
364 
365  /* attribute 11, type: STRUCT OF USINT, ARRAY of 6 USINTs, ARRAY of 28 USINTs default value: 0 */
366  memset(message_router_response->data, 0, 29);
367  message_router_response->data += 29;
368 
369  /* attribute 12, type: BOOL default value: 0 */
370  *(message_router_response->data) = 0;
371  message_router_response->data += 1;
372  }
373 
374  }
375  attribute++;
376  }
377  message_router_response->data_length = message_router_response->data
378  - response;
379  message_router_response->data = response;
380 
381  return kEipStatusOkSend;
382 }
383 
385  CipAttributeStruct *attribute = GetCipAttribute(instance, 13);
386  OPENER_ASSERT(NULL != attribute)
387  CipUint * data = (CipUint *) attribute->data;
388  EipUint16 encapsulation_inactivity_timeout = *data;
389  return encapsulation_inactivity_timeout;
390 }
391 
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 SetAttributeSingleTcp(CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
EipUint16 attribute_number
Definition: ciptypes.h:216
const CipOctet * data
Definition: ciptypes.h:191
Tracing infrastructure for OpENer.
EipUint16 number_of_attributes
Definition: ciptypes.h:244
EipStatus GetAttributeSingleTcpIpInterface(CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
CipAttributeStruct * attributes
Definition: ciptypes.h:229
CIP Message Router Request.
Definition: ciptypes.h:187
CipDword configuration_capability_
Class is a subclass of Instance.
Definition: ciptypes.h:237
#define OPENER_ASSERT(assertion)
EipUint16 GetEncapsulationInactivityTimeout(CipInstance *instance)
Public Method to get Encapsulation Inactivity Timeout Value.
EipUint32 GetDintFromMessage(const EipUint8 **const buffer)
Reads EIP_UINT32 from *buffer and converts little endian to host.
Definition: endianconv.c:83
Responsible for Endianess conversion.
size_t CalculateIndex(EipUint16 attribute_number)
Calculates Byte-Index of Attribute.
Definition: cipcommon.c:895
MulticastAddressConfiguration g_multicast_configuration
#9 The multicast configuration for this device
Multicast Configuration struct, called Mcast config.
CIP String.
Definition: ciptypes.h:138
EipStatus GetAttributeAllTcpIpInterface(CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
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
EipStatus
EIP stack status enum.
Definition: typedefs.h:93
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
uint32_t EipUint32
Definition: typedefs.h:34
#define OPENER_TRACE_INFO(...)
Definition: trace.h:89
CipUint g_encapsulation_inactivity_timeout
#13 Number of seconds of inactivity before TCP connection is closed
void CipFree(void *data)
Free memory allocated by the OpENer.
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
EipByte * string
Definition: ciptypes.h:140
CipInstance * GetCipInstance(const CipClass *RESTRICT const cip_class, EipUint32 instance_number)
Get a pointer to an instance.
CipEpath physical_link_object_
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.
Struct for saving TCP/IP interface information.
Definition: ciptypes.h:294
CipTcpIpNetworkInterfaceConfiguration interface_configuration_
EipUint16 attribute_number
Definition: ciptypes.h:156
uint8_t EipByte
EIP Data type definitions.
Definition: typedefs.h:28
CipDword configuration_control_
CipString hostname_
uint16_t CipUint
Definition: typedefs.h:47
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
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.
EipBool8 BeforeAssemblyDataSend(CipInstance *instance)
Inform the application that the data of an assembly object will be sent.
uint32_t CipDword
Definition: typedefs.h:45
uint16_t EipUint16
Definition: typedefs.h:33
EipStatus CipTcpIpInterfaceInit()
Initializing the data structures of the TCP/IP interface object.
CipDword tcp_status_
EipUint8 g_time_to_live_value
#8 the time to live value to be used for multi-cast connections
CipUsint size_of_additional_status
Definition: ciptypes.h:205