cipmessagerouter.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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 "endianconv.h"
  9. #include "ciperror.h"
  10. #include "trace.h"
  11. #include "enipmessage.h"
  12. #include "cipmessagerouter.h"
  13. CipMessageRouterRequest g_message_router_request;
  14. /** @brief A class registry list node
  15. *
  16. * A linked list of this object is the registry of classes known to the message router
  17. * for small devices with very limited memory it could make sense to change this list into an
  18. * array with a given max size for removing the need for having to dynamically allocate
  19. * memory. The size of the array could be a parameter in the platform config file.
  20. */
  21. typedef struct cip_message_router_object {
  22. struct cip_message_router_object *next; /**< link */
  23. CipClass *cip_class; /**< object */
  24. } CipMessageRouterObject;
  25. /** @brief Pointer to first registered object in MessageRouter*/
  26. CipMessageRouterObject *g_first_object = NULL;
  27. /** @brief Register a CIP Class to the message router
  28. * @param cip_class Pointer to a class object to be registered.
  29. * @return kEipStatusOk on success
  30. * kEipStatusError on no memory available to register more objects
  31. */
  32. EipStatus RegisterCipClass(CipClass *cip_class);
  33. /** @brief Create Message Router Request structure out of the received data.
  34. *
  35. * Parses the UCMM header consisting of: service, IOI size, IOI, data into a request structure
  36. * @param data pointer to the message data received
  37. * @param data_length number of bytes in the message
  38. * @param message_router_request pointer to structure of MRRequest data item.
  39. * @return kEipStatusOk on success. otherwise kEipStatusError
  40. */
  41. CipError CreateMessageRouterRequestStructure(const EipUint8 *data,
  42. EipInt16 data_length,
  43. CipMessageRouterRequest *message_router_request);
  44. void InitializeCipMessageRouterClass(CipClass *cip_class) {
  45. CipClass *meta_class = cip_class->class_instance.cip_class;
  46. InsertAttribute( (CipInstance *) cip_class, 1, kCipUint, EncodeCipUint, NULL,
  47. (void *) &cip_class->revision, kGetableSingleAndAll ); /* revision */
  48. InsertAttribute( (CipInstance *) cip_class, 2, kCipUint, EncodeCipUint, NULL,
  49. (void *) &cip_class->number_of_instances, kGetableSingle ); /* largest instance number */
  50. InsertAttribute( (CipInstance *) cip_class, 3, kCipUint, EncodeCipUint, NULL,
  51. (void *) &cip_class->number_of_instances, kGetableSingle ); /* number of instances currently existing*/
  52. InsertAttribute( (CipInstance *) cip_class, 4, kCipUint, EncodeCipUint, NULL,
  53. (void *) &kCipUintZero, kGetableAll ); /* optional attribute list - default = 0 */
  54. InsertAttribute( (CipInstance *) cip_class, 5, kCipUint, EncodeCipUint, NULL,
  55. (void *) &kCipUintZero, kGetableAll ); /* optional service list - default = 0 */
  56. InsertAttribute( (CipInstance *) cip_class, 6, kCipUint, EncodeCipUint, NULL,
  57. (void *) &meta_class->highest_attribute_number,
  58. kGetableSingleAndAll ); /* max class attribute number*/
  59. InsertAttribute( (CipInstance *) cip_class, 7, kCipUint, EncodeCipUint, NULL,
  60. (void *) &cip_class->highest_attribute_number,
  61. kGetableSingleAndAll ); /* max instance attribute number*/
  62. InsertService(meta_class,
  63. kGetAttributeAll,
  64. &GetAttributeAll,
  65. "GetAttributeAll"); /* bind instance services to the metaclass*/
  66. InsertService(meta_class,
  67. kGetAttributeSingle,
  68. &GetAttributeSingle,
  69. "GetAttributeSingle");
  70. }
  71. EipStatus CipMessageRouterInit() {
  72. CipClass *message_router = CreateCipClass(kCipMessageRouterClassCode, /* class code */
  73. 7, /* # of class attributes */
  74. 7, /* # highest class attribute number */
  75. 2, /* # of class services */
  76. 0, /* # of instance attributes */
  77. 0, /* # highest instance attribute number */
  78. 1, /* # of instance services */
  79. 1, /* # of instances */
  80. "message router", /* class name */
  81. 1, /* # class revision*/
  82. InitializeCipMessageRouterClass); /* # function pointer for initialization*/
  83. if(NULL == message_router) {
  84. return kEipStatusError;
  85. }
  86. InsertService(message_router,
  87. kGetAttributeSingle,
  88. &GetAttributeSingle,
  89. "GetAttributeSingle");
  90. /* reserved for future use -> set to zero */
  91. return kEipStatusOk;
  92. }
  93. /** @brief Get the registered MessageRouter object corresponding to ClassID.
  94. * given a class ID, return a pointer to the registration node for that object
  95. *
  96. * @param class_id Class code to be searched for.
  97. * @return Pointer to registered message router object
  98. * NULL .. Class not registered
  99. */
  100. CipMessageRouterObject *GetRegisteredObject(EipUint32 class_id) {
  101. CipMessageRouterObject *object = g_first_object; /* get pointer to head of class registration list */
  102. while(NULL != object) /* for each entry in list*/
  103. {
  104. OPENER_ASSERT(NULL != object->cip_class);
  105. if(object->cip_class->class_code == class_id) {
  106. return object; /* return registration node if it matches class ID*/
  107. }
  108. object = object->next;
  109. }
  110. return NULL;
  111. }
  112. CipClass *GetCipClass(const CipUdint class_code) {
  113. CipMessageRouterObject *message_router_object =
  114. GetRegisteredObject(class_code);
  115. if(message_router_object) {
  116. return message_router_object->cip_class;
  117. } else {
  118. return NULL;
  119. }
  120. }
  121. CipInstance *GetCipInstance(const CipClass *RESTRICT const cip_class,
  122. const CipInstanceNum instance_number) {
  123. if(instance_number == 0) {
  124. return (CipInstance *) cip_class; /* if the instance number is zero, return the class object itself*/
  125. }
  126. /* pointer to linked list of instances from the class object*/
  127. for(CipInstance *instance = cip_class->instances; instance;
  128. instance = instance->next) /* follow the list*/
  129. {
  130. if(instance->instance_number == instance_number) {
  131. return instance; /* if the number matches, return the instance*/
  132. }
  133. }
  134. return NULL;
  135. }
  136. EipStatus RegisterCipClass(CipClass *cip_class) {
  137. CipMessageRouterObject **message_router_object = &g_first_object;
  138. while(*message_router_object) {
  139. message_router_object = &(*message_router_object)->next; /* follow the list until p points to an empty link (list end)*/
  140. }
  141. *message_router_object =
  142. (CipMessageRouterObject *) CipCalloc(1, sizeof(CipMessageRouterObject) ); /* create a new node at the end of the list*/
  143. if(*message_router_object == 0) {
  144. return kEipStatusError; /* check for memory error*/
  145. }
  146. (*message_router_object)->cip_class = cip_class; /* fill in the new node*/
  147. (*message_router_object)->next = NULL;
  148. return kEipStatusOk;
  149. }
  150. EipStatus NotifyMessageRouter(EipUint8 *data,
  151. int data_length,
  152. CipMessageRouterResponse *message_router_response,
  153. const struct sockaddr *const originator_address,
  154. const CipSessionHandle encapsulation_session) {
  155. EipStatus eip_status = kEipStatusOkSend;
  156. CipError status = kCipErrorSuccess;
  157. OPENER_TRACE_INFO("NotifyMessageRouter: routing unconnected message\n");
  158. if(kCipErrorSuccess !=
  159. (status =
  160. CreateMessageRouterRequestStructure(data, data_length,
  161. &g_message_router_request) ) ) { /* error from create MR structure*/
  162. OPENER_TRACE_ERR(
  163. "NotifyMessageRouter: error from createMRRequeststructure\n");
  164. message_router_response->general_status = status;
  165. message_router_response->size_of_additional_status = 0;
  166. message_router_response->reserved = 0;
  167. message_router_response->reply_service =
  168. (0x80 | g_message_router_request.service);
  169. } else {
  170. /* forward request to appropriate Object if it is registered*/
  171. CipMessageRouterObject *registered_object = GetRegisteredObject(
  172. g_message_router_request.request_path.class_id);
  173. if(registered_object == 0) {
  174. OPENER_TRACE_ERR(
  175. "NotifyMessageRouter: sending CIP_ERROR_OBJECT_DOES_NOT_EXIST reply, class id 0x%x is not registered\n",
  176. (unsigned ) g_message_router_request.request_path.class_id);
  177. message_router_response->general_status = kCipErrorPathDestinationUnknown; /*according to the test tool this should be the correct error flag instead of CIP_ERROR_OBJECT_DOES_NOT_EXIST;*/
  178. message_router_response->size_of_additional_status = 0;
  179. message_router_response->reserved = 0;
  180. message_router_response->reply_service =
  181. (0x80 | g_message_router_request.service);
  182. } else {
  183. /* call notify function from Object with ClassID (gMRRequest.RequestPath.ClassID)
  184. object will or will not make an reply into gMRResponse*/
  185. message_router_response->reserved = 0;
  186. OPENER_ASSERT(NULL != registered_object->cip_class); OPENER_TRACE_INFO(
  187. "NotifyMessageRouter: calling notify function of class '%s'\n",
  188. registered_object->cip_class->class_name);
  189. eip_status = NotifyClass(registered_object->cip_class,
  190. &g_message_router_request,
  191. message_router_response,
  192. originator_address,
  193. encapsulation_session);
  194. #ifdef OPENER_TRACE_ENABLED
  195. if (eip_status == kEipStatusError) {
  196. OPENER_TRACE_ERR(
  197. "notifyMR: notify function of class '%s' returned an error\n",
  198. registered_object->cip_class->class_name);
  199. } else if (eip_status == kEipStatusOk) {
  200. OPENER_TRACE_INFO(
  201. "notifyMR: notify function of class '%s' returned no reply\n",
  202. registered_object->cip_class->class_name);
  203. } else {
  204. OPENER_TRACE_INFO(
  205. "notifyMR: notify function of class '%s' returned a reply\n",
  206. registered_object->cip_class->class_name);
  207. }
  208. #endif
  209. }
  210. }
  211. return eip_status;
  212. }
  213. CipError CreateMessageRouterRequestStructure(const EipUint8 *data,
  214. EipInt16 data_length,
  215. CipMessageRouterRequest *message_router_request)
  216. {
  217. message_router_request->service = *data;
  218. data++;
  219. data_length--;
  220. int number_of_decoded_bytes =
  221. DecodePaddedEPath(&(message_router_request->request_path), &data);
  222. if(number_of_decoded_bytes < 0) {
  223. return kCipErrorPathSegmentError;
  224. }
  225. message_router_request->data = data;
  226. message_router_request->request_data_size = data_length -
  227. number_of_decoded_bytes;
  228. if(message_router_request->request_data_size < 0) {
  229. return kCipErrorPathSizeInvalid;
  230. } else {
  231. return kCipErrorSuccess;
  232. }
  233. }
  234. void DeleteAllClasses(void) {
  235. CipMessageRouterObject *message_router_object = g_first_object; /* get pointer to head of class registration list */
  236. CipMessageRouterObject *message_router_object_to_delete = NULL;
  237. CipInstance *instance = NULL;
  238. CipInstance *instance_to_delete = NULL;
  239. while(NULL != message_router_object) {
  240. message_router_object_to_delete = message_router_object;
  241. message_router_object = message_router_object->next;
  242. instance = message_router_object_to_delete->cip_class->instances;
  243. while(NULL != instance) {
  244. instance_to_delete = instance;
  245. instance = instance->next;
  246. if(message_router_object_to_delete->cip_class->number_of_attributes) /* if the class has instance attributes */
  247. { /* then free storage for the attribute array */
  248. CipFree(instance_to_delete->attributes);
  249. }
  250. CipFree(instance_to_delete);
  251. }
  252. /* free meta class data*/
  253. CipClass *meta_class =
  254. message_router_object_to_delete->cip_class->class_instance.cip_class;
  255. CipFree(meta_class->class_name);
  256. CipFree(meta_class->services);
  257. CipFree(meta_class->get_single_bit_mask);
  258. CipFree(meta_class->set_bit_mask);
  259. CipFree(meta_class->get_all_bit_mask);
  260. CipFree(meta_class);
  261. /* free class data*/
  262. CipClass *cip_class = message_router_object_to_delete->cip_class;
  263. CipFree(cip_class->class_name);
  264. CipFree(cip_class->get_single_bit_mask);
  265. CipFree(cip_class->set_bit_mask);
  266. CipFree(cip_class->get_all_bit_mask);
  267. CipFree(cip_class->class_instance.attributes);
  268. CipFree(cip_class->services);
  269. CipFree(cip_class);
  270. /* free message router object */
  271. CipFree(message_router_object_to_delete);
  272. }
  273. g_first_object = NULL;
  274. }