cipmessagerouter.c 13 KB

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