OpENer - Open Source EtherNet/IP(TM) I/O Target Stack  2.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cipmessagerouter.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright (c) 2009, Rockwell Automation, Inc.
3  * All rights reserved.
4  *
5  ******************************************************************************/
6 #include "opener_api.h"
7 #include "cipcommon.h"
8 #include "cipmessagerouter.h"
9 #include "endianconv.h"
10 #include "ciperror.h"
11 #include "trace.h"
12 
15 
23 typedef struct cip_message_router_object {
27 
30 
37 
47  const EipUint8 *data,
48  EipInt16 data_length,
49  CipMessageRouterRequest *message_router_request);
50 
51 
53 
54  CipClass *meta_class = cip_class->class_instance.cip_class;
55 
56  InsertAttribute( (CipInstance *) cip_class, 1, kCipUint,
57  (void *) &cip_class->revision, kGetableSingleAndAll ); /* revision */
58  InsertAttribute( (CipInstance *) cip_class, 2, kCipUint,
59  (void *) &cip_class->number_of_instances,
60  kGetableSingle ); /* largest instance number */
61  InsertAttribute( (CipInstance *) cip_class, 3, kCipUint,
62  (void *) &cip_class->number_of_instances,
63  kGetableSingle ); /* number of instances currently existing*/
64  InsertAttribute( (CipInstance *) cip_class, 4, kCipUint,
65  (void *) &kCipUintZero,
66  kGetableAll ); /* optional attribute list - default = 0 */
67  InsertAttribute( (CipInstance *) cip_class, 5, kCipUint,
68  (void *) &kCipUintZero,
69  kGetableAll ); /* optional service list - default = 0 */
70  InsertAttribute( (CipInstance *) cip_class, 6, kCipUint,
71  (void *) &meta_class->highest_attribute_number,
72  kGetableSingleAndAll ); /* max class attribute number*/
73  InsertAttribute( (CipInstance *) cip_class, 7, kCipUint,
74  (void *) &cip_class->highest_attribute_number,
75  kGetableSingleAndAll ); /* max instance attribute number*/
76 }
77 
79 
80  CipClass *message_router = CreateCipClass(kCipMessageRouterClassCode, /* class ID*/
81  0, /* # of class attributes */
82  7, /* # highest class attribute number*/
83  2, /* # of class services*/
84  0, /* # of instance attributes*/
85  0, /* # highest instance attribute number*/
86  1, /* # of instance services*/
87  1, /* # of instances*/
88  "message router", /* class name*/
89  1, /* # class revision*/
90  InitializeCipMessageRouterClass); /* # function pointer for initialization*/
91  if (NULL == message_router) {
92  return kEipStatusError;
93  }
95  "GetAttributeSingle");
96 
97  /* reserved for future use -> set to zero */
98  g_message_router_response.reserved = 0;
99  g_message_router_response.data = g_message_data_reply_buffer; /* set reply buffer, using a fixed buffer (about 100 bytes) */
100 
101  return kEipStatusOk;
102 }
103 
112  CipMessageRouterObject *object = g_first_object; /* get pointer to head of class registration list */
113 
114  while (NULL != object) /* for each entry in list*/
115  {
116  OPENER_ASSERT(NULL != object->cip_class)
117  if (object->cip_class->class_id == class_id) {
118  return object; /* return registration node if it matches class ID*/
119  }
120  object = object->next;
121  }
122  return NULL;
123 }
124 
125 CipClass *GetCipClass(const EipUint32 class_id) {
126  CipMessageRouterObject *message_router_object = GetRegisteredObject(class_id);
127 
128  if (message_router_object) {
129  return message_router_object->cip_class;
130  } else {
131  return NULL;
132  }
133 }
134 
136  EipUint32 instance_number) {
137 
138  if (instance_number == 0) {
139  return (CipInstance *) cip_class; /* if the instance number is zero, return the class object itself*/
140 
141  }
142  /* pointer to linked list of instances from the class object*/
143  for (CipInstance *instance = cip_class->instances; instance; instance =
144  instance->next) /* follow the list*/
145  {
146  if (instance->instance_number == instance_number) {
147  return instance; /* if the number matches, return the instance*/
148  }
149  }
150 
151  return NULL;
152 }
153 
155  CipMessageRouterObject **message_router_object = &g_first_object;
156 
157  while (*message_router_object) {
158  message_router_object = &(*message_router_object)->next; /* follow the list until p points to an empty link (list end)*/
159 
160  }
161  *message_router_object = (CipMessageRouterObject *) CipCalloc(
162  1, sizeof(CipMessageRouterObject) ); /* create a new node at the end of the list*/
163  if (*message_router_object == 0) {
164  return kEipStatusError; /* check for memory error*/
165 
166  }
167  (*message_router_object)->cip_class = cip_class; /* fill in the new node*/
168  (*message_router_object)->next = NULL;
169 
170  return kEipStatusOk;
171 }
172 
174  int data_length,
175  const struct sockaddr *const originator_address,
176  const int encapsulation_session) {
177  EipStatus eip_status = kEipStatusOkSend;
178  EipByte status = kCipErrorSuccess;
179 
180  g_message_router_response.data = g_message_data_reply_buffer; /* set reply buffer, using a fixed buffer (about 100 bytes) */
181 
182  OPENER_TRACE_INFO("NotifyMessageRouter: routing unconnected message\n");
183  if ( kCipErrorSuccess
185  data, data_length, &g_message_router_request) ) ) { /* error from create MR structure*/
187  "NotifyMessageRouter: error from createMRRequeststructure\n");
188  g_message_router_response.general_status = status;
189  g_message_router_response.size_of_additional_status = 0;
190  g_message_router_response.reserved = 0;
191  g_message_router_response.data_length = 0;
192  g_message_router_response.reply_service = (0x80
193  | g_message_router_request.
194  service);
195  } else {
196  /* forward request to appropriate Object if it is registered*/
197  CipMessageRouterObject *registered_object = GetRegisteredObject(
198  g_message_router_request.request_path.class_id);
199  if (registered_object == 0) {
201  "NotifyMessageRouter: sending CIP_ERROR_OBJECT_DOES_NOT_EXIST reply, class id 0x%x is not registered\n",
202  (unsigned ) g_message_router_request.request_path.class_id);
203  g_message_router_response.general_status =
204  kCipErrorPathDestinationUnknown; /*according to the test tool this should be the correct error flag instead of CIP_ERROR_OBJECT_DOES_NOT_EXIST;*/
205  g_message_router_response.size_of_additional_status = 0;
206  g_message_router_response.reserved = 0;
207  g_message_router_response.data_length = 0;
208  g_message_router_response.reply_service = (0x80
209  | g_message_router_request.
210  service);
211  } else {
212  /* call notify function from Object with ClassID (gMRRequest.RequestPath.ClassID)
213  object will or will not make an reply into gMRResponse*/
214  g_message_router_response.reserved = 0;
215  OPENER_ASSERT(NULL != registered_object->cip_class)
217  "NotifyMessageRouter: calling notify function of class '%s'\n",
218  registered_object->cip_class->class_name);
219  eip_status = NotifyClass(registered_object->cip_class,
220  &g_message_router_request,
221  &g_message_router_response,
222  originator_address,
223  encapsulation_session);
224 
225 #ifdef OPENER_TRACE_ENABLED
226  if (eip_status == kEipStatusError) {
228  "notifyMR: notify function of class '%s' returned an error\n",
229  registered_object->cip_class->class_name);
230  } else if (eip_status == kEipStatusOk) {
232  "notifyMR: notify function of class '%s' returned no reply\n",
233  registered_object->cip_class->class_name);
234  } else {
236  "notifyMR: notify function of class '%s' returned a reply\n",
237  registered_object->cip_class->class_name);
238  }
239 #endif
240  }
241  }
242  return eip_status;
243 }
244 
246  const EipUint8 *data,
247  EipInt16 data_length,
248  CipMessageRouterRequest *message_router_request) {
249 
250  message_router_request->service = *data;
251  data++;
252  data_length--;
253 
254  int number_of_decoded_bytes = DecodePaddedEPath(
255  &(message_router_request->request_path), &data);
256  if (number_of_decoded_bytes < 0) {
258  }
259 
260  message_router_request->data = data;
261  message_router_request->request_path_size = data_length
262  - number_of_decoded_bytes;
263 
264  if (message_router_request->request_path_size < 0) {
266  } else {
267  return kCipErrorSuccess;
268  }
269 }
270 
271 void DeleteAllClasses(void) {
272  CipMessageRouterObject *message_router_object = g_first_object; /* get pointer to head of class registration list */
273  CipMessageRouterObject *message_router_object_to_delete = NULL;
274  CipInstance *instance = NULL;
275  CipInstance *instance_to_delete = NULL;
276 
277  while (NULL != message_router_object) {
278  message_router_object_to_delete = message_router_object;
279  message_router_object = message_router_object->next;
280 
281  instance = message_router_object_to_delete->cip_class->instances;
282  while (NULL != instance) {
283  instance_to_delete = instance;
284  instance = instance->next;
285  if (message_router_object_to_delete->cip_class->number_of_attributes) /* if the class has instance attributes */
286  { /* then free storage for the attribute array */
287  CipFree(instance_to_delete->attributes);
288  }
289  CipFree(instance_to_delete);
290  }
291 
292  /*clear meta class data*/
293  CipFree(
294  message_router_object_to_delete->cip_class->class_instance.cip_class
295  ->class_name);
296  CipFree(
297  message_router_object_to_delete->cip_class->class_instance.cip_class
298  ->services);
299  CipFree(
300  message_router_object_to_delete->cip_class->class_instance.cip_class);
301  /*clear class data*/
302  CipFree(
303  message_router_object_to_delete->cip_class->class_instance.attributes);
304  CipFree(message_router_object_to_delete->cip_class->services);
305  CipFree(message_router_object_to_delete->cip_class);
306  CipFree(message_router_object_to_delete);
307  }
308  g_first_object = NULL;
309 }
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 cip_service_struct * services
Definition: ciptypes.h:256
CipMessageRouterObject * GetRegisteredObject(EipUint32 class_id)
Get the registered MessageRouter object corresponding to ClassID. given a class ID, return a pointer to the registration node for that object.
const CipOctet * data
Definition: ciptypes.h:191
EipUint16 number_of_instances
Definition: ciptypes.h:242
Tracing infrastructure for OpENer.
EipStatus NotifyMessageRouter(EipUint8 *data, int data_length, const struct sockaddr *const originator_address, const int encapsulation_session)
Notify the MessageRouter that an explicit message (connected or unconnected) has been received...
EipUint16 number_of_attributes
Definition: ciptypes.h:244
int DecodePaddedEPath(CipEpath *epath, const EipUint8 **message)
Decodes padded EPath.
Definition: cipcommon.c:804
CipAttributeStruct * attributes
Definition: ciptypes.h:229
CipMessageRouterRequest g_message_router_request
CIP Message Router Request.
Definition: ciptypes.h:187
EipUint32 class_id
Definition: ciptypes.h:240
char * class_name
Definition: ciptypes.h:257
CipError CreateMessageRouterRequestStructure(const EipUint8 *data, EipInt16 data_length, CipMessageRouterRequest *message_router_request)
Create Message Router Request structure out of the received data.
Class is a subclass of Instance.
Definition: ciptypes.h:237
#define OPENER_ASSERT(assertion)
CipInstance * instances
Definition: ciptypes.h:255
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
Responsible for Endianess conversion.
#define OPENER_TRACE_ERR(...)
Definition: trace.h:86
struct cip_message_router_object * next
EipUint8 g_message_data_reply_buffer[OPENER_MESSAGE_DATA_REPLY_BUFFER]
Definition: cipcommon.c:30
CipMessageRouterObject * g_first_object
Pointer to first registered object in MessageRouter.
void * CipCalloc(size_t number_of_elements, size_t size_of_element)
Allocate memory for the CIP stack.
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
void InitializeCipMessageRouterClass(CipClass *cip_class)
void DeleteAllClasses(void)
Free all data allocated by the classes created in the CIP stack.
EipStatus
EIP stack status enum.
Definition: typedefs.h:93
uint8_t EipUint8
Definition: typedefs.h:32
CipMessageRouterResponse g_message_router_response
Structure for storing the Response generated by an explict message.
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
struct cip_instance * next
Definition: ciptypes.h:232
EipStatus CipMessageRouterInit()
Initialize the data structures of the message router.
#define OPENER_TRACE_INFO(...)
Definition: trace.h:89
void CipFree(void *data)
Free memory allocated by the OpENer.
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
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.
EipUint16 class_id
Definition: ciptypes.h:154
A class registry list node.
uint8_t EipByte
EIP Data type definitions.
Definition: typedefs.h:28
int16_t EipInt16
Definition: typedefs.h:30
EipUint16 highest_attribute_number
Definition: ciptypes.h:245
CIP Message Router Response.
Definition: ciptypes.h:199
struct cip_class * cip_class
Definition: ciptypes.h:231
EipInt16 request_path_size
Definition: ciptypes.h:190
struct cip_message_router_object CipMessageRouterObject
A class registry list node.
CipUsint size_of_additional_status
Definition: ciptypes.h:205
CipError
Definition: ciperror.h:9