cpf.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. /*******************************************************************************
  2. * Copyright (c) 2009, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. #include <string.h>
  7. #include "cpf.h"
  8. #include "opener_api.h"
  9. #include "cipcommon.h"
  10. #include "cipmessagerouter.h"
  11. #include "endianconv.h"
  12. #include "ciperror.h"
  13. #include "cipconnectionmanager.h"
  14. #include "trace.h"
  15. #include "encap.h"
  16. #include "enipmessage.h"
  17. const size_t kItemCountFieldSize = 2; /**< The size of the item count field in the message */
  18. const size_t KItemDataTypeIdFieldLength = 2; /**< The size of the item count field in the message */
  19. /** @brief Size, in bytes, of the encoded sequenced address item data field.
  20. *
  21. * Data type and value per @cite CipVol2, Table 2-6.6.
  22. */
  23. const EipUint16 kSequencedAddressItemLength = 8;
  24. CipCommonPacketFormatData g_common_packet_format_data_item; /**< CPF global data items */
  25. static void InitializeMessageRouterResponse(
  26. CipMessageRouterResponse *const message_router_response) {
  27. memset(message_router_response, 0, sizeof(*message_router_response) );
  28. InitializeENIPMessage(&message_router_response->message);
  29. }
  30. EipStatus NotifyCommonPacketFormat(const EncapsulationData *const received_data,
  31. const struct sockaddr *const originator_address,
  32. ENIPMessage *const outgoing_message) {
  33. EipStatus return_value = kEipStatusError;
  34. CipMessageRouterResponse message_router_response;
  35. InitializeMessageRouterResponse(&message_router_response);
  36. if(kEipStatusError
  37. == (return_value =
  38. CreateCommonPacketFormatStructure(received_data->
  39. current_communication_buffer_position,
  40. received_data->data_length,
  41. &
  42. g_common_packet_format_data_item) ) )
  43. {
  44. OPENER_TRACE_ERR("notifyCPF: error from createCPFstructure\n");
  45. } else {
  46. return_value = kEipStatusOkSend; /* In cases of errors we normally need to send an error response */
  47. if(g_common_packet_format_data_item.address_item.type_id ==
  48. kCipItemIdNullAddress) /* check if NullAddressItem received, otherwise it is no unconnected message and should not be here*/
  49. { /* found null address item*/
  50. if(g_common_packet_format_data_item.data_item.type_id ==
  51. kCipItemIdUnconnectedDataItem) { /* unconnected data item received*/
  52. return_value = NotifyMessageRouter(
  53. g_common_packet_format_data_item.data_item.data,
  54. g_common_packet_format_data_item.data_item.length,
  55. &message_router_response,
  56. originator_address,
  57. received_data->session_handle);
  58. if(return_value != kEipStatusError) {
  59. SkipEncapsulationHeader(outgoing_message);
  60. /* TODO: Here we get the status. What to do? kEipStatusError from AssembleLinearMessage().
  61. * Its not clear how to transport this error information to the requester. */
  62. EipStatus status = AssembleLinearMessage(&message_router_response,
  63. &g_common_packet_format_data_item,
  64. outgoing_message);
  65. (void)status; /* Suppress unused variable warning. */
  66. /* Save pointer and move to start for Encapusulation Header */
  67. CipOctet *buffer = outgoing_message->current_message_position;
  68. outgoing_message->current_message_position =
  69. outgoing_message->message_buffer;
  70. GenerateEncapsulationHeader(received_data,
  71. outgoing_message->used_message_length,
  72. received_data->session_handle,
  73. kEncapsulationProtocolSuccess,
  74. outgoing_message);
  75. /* Move pointer back to last octet */
  76. outgoing_message->current_message_position = buffer;
  77. return_value = kEipStatusOkSend;
  78. }
  79. } else {
  80. /* wrong data item detected*/
  81. OPENER_TRACE_ERR(
  82. "notifyCPF: got something besides the expected CIP_ITEM_ID_UNCONNECTEDMESSAGE\n");
  83. GenerateEncapsulationHeader(received_data,
  84. 0,
  85. received_data->session_handle,
  86. kEncapsulationProtocolIncorrectData,
  87. outgoing_message);
  88. return_value = kEipStatusOkSend;
  89. }
  90. } else {
  91. OPENER_TRACE_ERR(
  92. "notifyCPF: got something besides the expected CIP_ITEM_ID_NULL\n");
  93. GenerateEncapsulationHeader(received_data,
  94. 0,
  95. received_data->session_handle,
  96. kEncapsulationProtocolIncorrectData,
  97. outgoing_message);
  98. return_value = kEipStatusOkSend;
  99. }
  100. }
  101. return return_value;
  102. }
  103. EipStatus NotifyConnectedCommonPacketFormat(
  104. const EncapsulationData *const received_data,
  105. const struct sockaddr *const originator_address,
  106. ENIPMessage *const outgoing_message) {
  107. EipStatus return_value = CreateCommonPacketFormatStructure(
  108. received_data->current_communication_buffer_position,
  109. received_data->data_length,
  110. &g_common_packet_format_data_item);
  111. if(kEipStatusError == return_value) {
  112. OPENER_TRACE_ERR("notifyConnectedCPF: error from createCPFstructure\n");
  113. } else {
  114. return_value = kEipStatusError; /* For connected explicit messages status always has to be 0*/
  115. if(g_common_packet_format_data_item.address_item.type_id ==
  116. kCipItemIdConnectionAddress) /* check if ConnectedAddressItem received, otherwise it is no connected message and should not be here*/
  117. { /* ConnectedAddressItem item */
  118. CipConnectionObject *connection_object = GetConnectedObject(
  119. g_common_packet_format_data_item.address_item.data.connection_identifier);
  120. if(NULL != connection_object) {
  121. /* reset the watchdog timer */
  122. ConnectionObjectResetInactivityWatchdogTimerValue(connection_object);
  123. /*TODO check connection id and sequence count */
  124. if(g_common_packet_format_data_item.data_item.type_id ==
  125. kCipItemIdConnectedDataItem) { /* connected data item received*/
  126. EipUint8 *buffer = g_common_packet_format_data_item.data_item.data;
  127. g_common_packet_format_data_item.address_item.data.sequence_number =
  128. GetUintFromMessage( (const EipUint8 **const ) &buffer );
  129. OPENER_TRACE_INFO(
  130. "Class 3 sequence number: %d, last sequence number: %d\n",
  131. g_common_packet_format_data_item.address_item.data.sequence_number,
  132. connection_object->sequence_count_consuming);
  133. if(connection_object->sequence_count_consuming ==
  134. g_common_packet_format_data_item.address_item.data.sequence_number)
  135. {
  136. memcpy(outgoing_message,
  137. &(connection_object->last_reply_sent),
  138. sizeof(ENIPMessage) );
  139. outgoing_message->current_message_position =
  140. outgoing_message->message_buffer;
  141. /* Regenerate encapsulation header for new message */
  142. outgoing_message->used_message_length -=
  143. ENCAPSULATION_HEADER_LENGTH;
  144. GenerateEncapsulationHeader(received_data,
  145. outgoing_message->used_message_length,
  146. received_data->session_handle,
  147. kEncapsulationProtocolSuccess,
  148. outgoing_message);
  149. outgoing_message->current_message_position = buffer;
  150. /* End regenerate encapsulation header for new message */
  151. return kEipStatusOkSend;
  152. }
  153. connection_object->sequence_count_consuming =
  154. g_common_packet_format_data_item.address_item.data.sequence_number;
  155. ConnectionObjectResetInactivityWatchdogTimerValue(connection_object);
  156. CipMessageRouterResponse message_router_response;
  157. InitializeMessageRouterResponse(&message_router_response);
  158. return_value = NotifyMessageRouter(buffer,
  159. g_common_packet_format_data_item.data_item.length - 2,
  160. &message_router_response,
  161. originator_address,
  162. received_data->session_handle);
  163. if(return_value != kEipStatusError) {
  164. g_common_packet_format_data_item.address_item.data.
  165. connection_identifier =
  166. connection_object->cip_produced_connection_id;
  167. SkipEncapsulationHeader(outgoing_message);
  168. /* TODO: Here we get the status. What to do? kEipStatusError from AssembleLinearMessage().
  169. * Its not clear how to transport this error information to the requester. */
  170. EipStatus status = AssembleLinearMessage(&message_router_response,
  171. &g_common_packet_format_data_item,
  172. outgoing_message);
  173. (void)status; /* Suppress unused variable warning. */
  174. CipOctet *pos = outgoing_message->current_message_position;
  175. outgoing_message->current_message_position =
  176. outgoing_message->message_buffer;
  177. GenerateEncapsulationHeader(received_data,
  178. outgoing_message->used_message_length,
  179. received_data->session_handle,
  180. kEncapsulationProtocolSuccess,
  181. outgoing_message);
  182. outgoing_message->current_message_position = pos;
  183. memcpy(&connection_object->last_reply_sent,
  184. outgoing_message,
  185. sizeof(ENIPMessage) );
  186. return_value = kEipStatusOkSend;
  187. }
  188. } else {
  189. /* wrong data item detected*/
  190. OPENER_TRACE_ERR(
  191. "notifyConnectedCPF: got something besides the expected CIP_ITEM_ID_UNCONNECTEDMESSAGE\n");
  192. }
  193. } else {
  194. OPENER_TRACE_ERR(
  195. "notifyConnectedCPF: connection with given ID could not be found\n");
  196. }
  197. } else {
  198. OPENER_TRACE_ERR(
  199. "notifyConnectedCPF: got something besides the expected CIP_ITEM_ID_NULL\n");
  200. }
  201. }
  202. // return outgoing_message->used_message_length;
  203. return (0 !=
  204. outgoing_message->used_message_length ? kEipStatusOkSend :
  205. kEipStatusOk); /* TODO: What would the right EipStatus to return? */
  206. }
  207. /**
  208. * @brief Creates Common Packet Format structure out of data.
  209. * @param data Pointer to data which need to be structured.
  210. * @param data_length Length of data in pa_Data.
  211. * @param common_packet_format_data Pointer to structure of CPF data item.
  212. *
  213. * @return kEipStatusOk .. success
  214. * kEipStatusError .. error
  215. */
  216. EipStatus CreateCommonPacketFormatStructure(const EipUint8 *data,
  217. size_t data_length,
  218. CipCommonPacketFormatData *common_packet_format_data)
  219. {
  220. common_packet_format_data->address_info_item[0].type_id = 0;
  221. common_packet_format_data->address_info_item[1].type_id = 0;
  222. size_t length_count = 0;
  223. CipUint item_count = GetUintFromMessage(&data);
  224. //OPENER_ASSERT(4U >= item_count);/* Sanitizing data - probably needs to be changed for productive code */
  225. common_packet_format_data->item_count = item_count;
  226. length_count += 2;
  227. if(common_packet_format_data->item_count >= 1U) {
  228. common_packet_format_data->address_item.type_id = GetUintFromMessage(&data);
  229. common_packet_format_data->address_item.length = GetUintFromMessage(&data);
  230. length_count += 4;
  231. if(common_packet_format_data->address_item.length >= 4) {
  232. common_packet_format_data->address_item.data.connection_identifier =
  233. GetUdintFromMessage(&data);
  234. length_count += 4;
  235. }
  236. if(common_packet_format_data->address_item.length == 8) {
  237. common_packet_format_data->address_item.data.sequence_number =
  238. GetUdintFromMessage(&data);
  239. length_count += 4;
  240. }
  241. }
  242. if(common_packet_format_data->item_count >= 2) {
  243. common_packet_format_data->data_item.type_id = GetUintFromMessage(&data);
  244. common_packet_format_data->data_item.length = GetUintFromMessage(&data);
  245. common_packet_format_data->data_item.data = (EipUint8 *) data;
  246. if(data_length >=
  247. length_count + 4 + common_packet_format_data->data_item.length) {
  248. data += common_packet_format_data->data_item.length;
  249. length_count += (4 + common_packet_format_data->data_item.length);
  250. } else {
  251. return kEipStatusError;
  252. }
  253. /* Data type per CIP Volume 2, Edition 1.4, Table 2-6.1. */
  254. CipUint address_item_count = (CipUint)(common_packet_format_data->item_count - 2U);
  255. for(size_t j = 0; j < (address_item_count > 2 ? 2 : address_item_count);
  256. j++) /* TODO there needs to be a limit check here???*/
  257. {
  258. common_packet_format_data->address_info_item[j].type_id =
  259. GetIntFromMessage(&data);
  260. OPENER_TRACE_INFO("Sockaddr type id: %x\n",
  261. common_packet_format_data->address_info_item[j].type_id);
  262. length_count += 2;
  263. if( (common_packet_format_data->address_info_item[j].type_id ==
  264. kCipItemIdSocketAddressInfoOriginatorToTarget)
  265. || (common_packet_format_data->address_info_item[j].type_id ==
  266. kCipItemIdSocketAddressInfoTargetToOriginator) ) {
  267. common_packet_format_data->address_info_item[j].length =
  268. GetIntFromMessage(&data);
  269. common_packet_format_data->address_info_item[j].sin_family =
  270. GetIntFromMessage(&data);
  271. common_packet_format_data->address_info_item[j].sin_port =
  272. GetIntFromMessage(&data);
  273. common_packet_format_data->address_info_item[j].sin_addr =
  274. GetUdintFromMessage(&data);
  275. for(size_t i = 0; i < 8; i++) {
  276. common_packet_format_data->address_info_item[j].nasin_zero[i] = *data;
  277. data++;
  278. }
  279. length_count += 18;
  280. } else { /* no sockaddr item found */
  281. common_packet_format_data->address_info_item[j].type_id = 0; /* mark as not set */
  282. data -= 2;
  283. }
  284. }
  285. }
  286. /* set the addressInfoItems to not set if they were not received */
  287. if(common_packet_format_data->item_count < 4) {
  288. common_packet_format_data->address_info_item[1].type_id = 0;
  289. if(common_packet_format_data->item_count < 3) {
  290. common_packet_format_data->address_info_item[0].type_id = 0;
  291. }
  292. }
  293. if(length_count == data_length) { /* length of data is equal to length of Addr and length of Data */
  294. return kEipStatusOk;
  295. } else {
  296. OPENER_TRACE_WARN(
  297. "something is wrong with the length in Message Router @ CreateCommonPacketFormatStructure\n");
  298. if(common_packet_format_data->item_count > 2) {
  299. /* there is an optional packet in data stream which is not sockaddr item */
  300. return kEipStatusOk;
  301. } else { /* something with the length was wrong */
  302. return kEipStatusError;
  303. }
  304. }
  305. }
  306. /**
  307. * @brief Encodes a Null Address Item into the message frame
  308. * @param outgoing_message The outgoing message object
  309. */
  310. void EncodeNullAddressItem(ENIPMessage *const outgoing_message) {
  311. AddIntToMessage(kCipItemIdNullAddress, outgoing_message);
  312. /* null address item -> address length set to 0 */
  313. AddIntToMessage(0, outgoing_message);
  314. }
  315. /**
  316. * Encodes a Connected Address Item into the message frame
  317. * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  318. * @param outgoing_message The outgoing message object
  319. */
  320. void EncodeConnectedAddressItem(
  321. const CipCommonPacketFormatData *const common_packet_format_data_item,
  322. ENIPMessage *const outgoing_message) {
  323. /* connected data item -> address length set to 4 and copy ConnectionIdentifier */
  324. AddIntToMessage(kCipItemIdConnectionAddress, outgoing_message);
  325. AddIntToMessage(4, outgoing_message);
  326. AddDintToMessage(
  327. common_packet_format_data_item->address_item.data.connection_identifier,
  328. outgoing_message);
  329. }
  330. /**
  331. * @brief Encodes a sequenced address item into the message
  332. *
  333. * @param common_packet_format_data_item Common Packet Format item which is used in the encoding
  334. * @param outgoing_message The outgoing message object
  335. */
  336. void EncodeSequencedAddressItem(
  337. const CipCommonPacketFormatData *const common_packet_format_data_item,
  338. ENIPMessage *const outgoing_message) {
  339. /* sequenced address item -> address length set to 8 and copy ConnectionIdentifier and SequenceNumber */
  340. AddIntToMessage(kCipItemIdSequencedAddressItem, outgoing_message);
  341. AddIntToMessage(kSequencedAddressItemLength, outgoing_message);
  342. AddDintToMessage(
  343. common_packet_format_data_item->address_item.data.connection_identifier,
  344. outgoing_message);
  345. AddDintToMessage(
  346. common_packet_format_data_item->address_item.data.sequence_number,
  347. outgoing_message);
  348. }
  349. /**
  350. * @brief Adds the item count to the message frame
  351. *
  352. * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  353. * @param outgoing_message The outgoing message object
  354. */
  355. void EncodeItemCount(
  356. const CipCommonPacketFormatData *const common_packet_format_data_item,
  357. ENIPMessage *const outgoing_message) {
  358. AddIntToMessage(common_packet_format_data_item->item_count, outgoing_message); /* item count */
  359. }
  360. /**
  361. * Adds the data item type to the message frame
  362. *
  363. * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  364. * @param outgoing_message The outgoing message object
  365. */
  366. void EncodeDataItemType(
  367. const CipCommonPacketFormatData *const common_packet_format_data_item,
  368. ENIPMessage *const outgoing_message) {
  369. AddIntToMessage(common_packet_format_data_item->data_item.type_id,
  370. outgoing_message);
  371. }
  372. /**
  373. * Adds the data item section length to the message frame
  374. *
  375. * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  376. * @param outgoing_message The outgoing message object
  377. */
  378. void EncodeDataItemLength(
  379. const CipCommonPacketFormatData *const common_packet_format_data_item,
  380. ENIPMessage *const outgoing_message) {
  381. AddIntToMessage(common_packet_format_data_item->data_item.length,
  382. outgoing_message);
  383. }
  384. /**
  385. * Adds the data items to the message frame
  386. *
  387. * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  388. * @param outgoing_message The outgoing message object
  389. */
  390. void EncodeDataItemData(
  391. const CipCommonPacketFormatData *const common_packet_format_data_item,
  392. ENIPMessage *const outgoing_message) {
  393. memcpy(outgoing_message->current_message_position,
  394. common_packet_format_data_item->data_item.data,
  395. common_packet_format_data_item->data_item.length);
  396. outgoing_message->current_message_position +=
  397. common_packet_format_data_item->data_item.length;
  398. outgoing_message->used_message_length +=
  399. common_packet_format_data_item->data_item.length;
  400. }
  401. /**
  402. * @brief Encodes the Connected Data item length
  403. *
  404. * @param message_router_response The Router Response message which shall be answered
  405. * @param outgoing_message The outgoing message object
  406. */
  407. void EncodeConnectedDataItemLength(
  408. const CipMessageRouterResponse *const message_router_response,
  409. ENIPMessage *const outgoing_message) {
  410. AddIntToMessage( (EipUint16) (message_router_response->message.
  411. used_message_length + 4 + 2 /* TODO: Magic numbers */
  412. + (2 *
  413. message_router_response->
  414. size_of_additional_status) ),
  415. outgoing_message );
  416. }
  417. /**
  418. * @brief Encodes a sequence number into the message
  419. *
  420. * @param common_packet_format_data_item
  421. * @param outgoing_message The outgoing message object
  422. */
  423. void EncodeSequenceNumber(
  424. const CipCommonPacketFormatData *const common_packet_format_data_item,
  425. ENIPMessage *const outgoing_message) {
  426. AddIntToMessage(
  427. (EipUint16) common_packet_format_data_item->address_item.data.sequence_number,
  428. outgoing_message );
  429. }
  430. /**
  431. * @brief Encodes the reply service code for the requested service
  432. *
  433. * @param message_router_response The router response message data structure to be processed
  434. * @param outgoing_message The outgoing message object
  435. */
  436. void EncodeReplyService(
  437. const CipMessageRouterResponse *const message_router_response,
  438. ENIPMessage *const outgoing_message) {
  439. AddSintToMessage(message_router_response->reply_service, outgoing_message);
  440. }
  441. /**
  442. * @brief Encodes the reserved byte in the message router response
  443. *
  444. * @param message_router_response Router Response message to be processed
  445. * @param outgoing_message The outgoing message object
  446. */
  447. void EncodeReservedFieldOfLengthByte(
  448. const CipMessageRouterResponse *const message_router_response,
  449. ENIPMessage *const outgoing_message) {
  450. AddSintToMessage(message_router_response->reserved, outgoing_message);
  451. }
  452. /**
  453. * @brief Encodes the general status of a Router Response
  454. *
  455. * @param message_router_response Router Response message to be processed
  456. * @param outgoing_message The outgoing message object
  457. */
  458. void EncodeGeneralStatus(
  459. const CipMessageRouterResponse *const message_router_response,
  460. ENIPMessage *const outgoing_message) {
  461. AddSintToMessage(message_router_response->general_status, outgoing_message);
  462. }
  463. /**
  464. * @brief Encodes the length of the extended status data part
  465. *
  466. * @param message_router_response Router Response message to be processed
  467. * @param outgoing_message The outgoing message object
  468. */
  469. void EncodeExtendedStatusLength(
  470. const CipMessageRouterResponse *const message_router_response,
  471. ENIPMessage *const outgoing_message) {
  472. AddSintToMessage(message_router_response->size_of_additional_status,
  473. outgoing_message);
  474. }
  475. /**
  476. * @brief Encodes the extended status data items
  477. *
  478. * @param message_router_response Router Response message to be processed
  479. * @param outgoing_message The outgoing message object
  480. */
  481. void EncodeExtendedStatusDataItems(
  482. const CipMessageRouterResponse *const message_router_response,
  483. ENIPMessage *const outgoing_message) {
  484. for(size_t i = 0;
  485. i < message_router_response->size_of_additional_status &&
  486. i < MAX_SIZE_OF_ADD_STATUS; i++) {
  487. AddIntToMessage(message_router_response->additional_status[i],
  488. outgoing_message);
  489. }
  490. }
  491. /**
  492. * @brief Encodes the extended status (length and data) into the message
  493. *
  494. * This function uses EncodeExtendedStatusLength and EncodeExtendedStatusDataItems
  495. * to encode the complete extended status information into the message
  496. *
  497. * @param message_router_response Router Response message to be processed
  498. * @param outgoing_message The outgoing message object
  499. */
  500. void EncodeExtendedStatus(
  501. const CipMessageRouterResponse *const message_router_response,
  502. ENIPMessage *const outgoing_message) {
  503. EncodeExtendedStatusLength(message_router_response, outgoing_message);
  504. EncodeExtendedStatusDataItems(message_router_response, outgoing_message);
  505. }
  506. /**
  507. * @brief Encode the data item length of the unconnected data segment
  508. *
  509. * @param message_router_response Router Response message to be processed
  510. * @param outgoing_message The outgoing message object
  511. *
  512. */
  513. void EncodeUnconnectedDataItemLength(
  514. const CipMessageRouterResponse *const message_router_response,
  515. ENIPMessage *const outgoing_message) {
  516. AddIntToMessage( (EipUint16) (message_router_response->message.
  517. used_message_length + 4 /* TODO: Magic number */
  518. + (2 *
  519. message_router_response->
  520. size_of_additional_status) ),
  521. outgoing_message );
  522. }
  523. /**
  524. * @brief Encodes the Message Router Response data
  525. *
  526. * @param message_router_response Router Response message to be processed
  527. * @param outgoing_message The outgoing message object
  528. */
  529. void EncodeMessageRouterResponseData(
  530. const CipMessageRouterResponse *const message_router_response,
  531. ENIPMessage *const outgoing_message) {
  532. memcpy(outgoing_message->current_message_position,
  533. message_router_response->message.message_buffer,
  534. message_router_response->message.used_message_length);
  535. outgoing_message->current_message_position +=
  536. message_router_response->message.used_message_length;
  537. outgoing_message->used_message_length +=
  538. message_router_response->message.used_message_length;
  539. }
  540. /**
  541. * @brief Encodes the sockaddr info type id into the message
  542. *
  543. * @param item_type
  544. * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  545. * @param outgoing_message The outgoing message object
  546. */
  547. void EncodeSockaddrInfoItemTypeId(int item_type,
  548. const CipCommonPacketFormatData *const common_packet_format_data_item,
  549. ENIPMessage *const outgoing_message) {
  550. OPENER_ASSERT(item_type == 0 || item_type == 1);
  551. AddIntToMessage(
  552. common_packet_format_data_item->address_info_item[item_type].type_id,
  553. outgoing_message);
  554. }
  555. /**
  556. * @brief Encodes the sockaddr info length into the message
  557. *
  558. * @param item_type
  559. * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  560. * @param outgoing_message The outgoing message object
  561. */
  562. void EncodeSockaddrInfoLength(int item_type,
  563. const CipCommonPacketFormatData *const common_packet_format_data_item,
  564. ENIPMessage *const outgoing_message) {
  565. AddIntToMessage(
  566. common_packet_format_data_item->address_info_item[item_type].length,
  567. outgoing_message);
  568. }
  569. EipStatus AssembleLinearMessage(
  570. const CipMessageRouterResponse *const message_router_response,
  571. const CipCommonPacketFormatData *const common_packet_format_data_item,
  572. ENIPMessage *const outgoing_message) {
  573. if(message_router_response) {
  574. /* add Interface Handle and Timeout = 0 -> only for SendRRData and SendUnitData necessary */
  575. AddDintToMessage(0, outgoing_message);
  576. AddIntToMessage(0, outgoing_message);
  577. }
  578. EncodeItemCount(common_packet_format_data_item, outgoing_message);
  579. /* process Address Item */
  580. switch(common_packet_format_data_item->address_item.type_id) {
  581. case kCipItemIdNullAddress: {
  582. EncodeNullAddressItem(outgoing_message);
  583. break;
  584. }
  585. case kCipItemIdConnectionAddress: {
  586. EncodeConnectedAddressItem(common_packet_format_data_item,
  587. outgoing_message);
  588. break;
  589. }
  590. case kCipItemIdSequencedAddressItem: {
  591. EncodeSequencedAddressItem(common_packet_format_data_item,
  592. outgoing_message);
  593. break;
  594. }
  595. default:
  596. OPENER_TRACE_INFO("Unknown CIP Item in AssembleLinearMessage");
  597. return kEipStatusError;
  598. }
  599. /* process Data Item */
  600. if( (common_packet_format_data_item->data_item.type_id ==
  601. kCipItemIdUnconnectedDataItem)
  602. || (common_packet_format_data_item->data_item.type_id ==
  603. kCipItemIdConnectedDataItem) ) {
  604. if(message_router_response) {
  605. EncodeDataItemType(common_packet_format_data_item, outgoing_message);
  606. if(common_packet_format_data_item->data_item.type_id ==
  607. kCipItemIdConnectedDataItem) { /* Connected Item */
  608. EncodeConnectedDataItemLength(message_router_response,
  609. outgoing_message);
  610. EncodeSequenceNumber(&g_common_packet_format_data_item,
  611. outgoing_message);
  612. } else { /* Unconnected Item */
  613. EncodeUnconnectedDataItemLength(message_router_response,
  614. outgoing_message);
  615. }
  616. /* write message router response into linear memory */
  617. EncodeReplyService(message_router_response, outgoing_message);
  618. EncodeReservedFieldOfLengthByte(message_router_response,
  619. outgoing_message);
  620. EncodeGeneralStatus(message_router_response, outgoing_message);
  621. EncodeExtendedStatus(message_router_response, outgoing_message);
  622. EncodeMessageRouterResponseData(message_router_response,
  623. outgoing_message);
  624. } else { /* connected IO Message to send */
  625. EncodeDataItemType(common_packet_format_data_item, outgoing_message);
  626. EncodeDataItemLength(common_packet_format_data_item, outgoing_message);
  627. EncodeDataItemData(common_packet_format_data_item, outgoing_message);
  628. }
  629. }
  630. /* process SockAddr Info Items */
  631. /* make sure first the O->T and then T->O appears on the wire.
  632. * EtherNet/IP specification doesn't demand it, but there are EIP
  633. * devices which depend on CPF items to appear in the order of their
  634. * ID number */
  635. for(int type = kCipItemIdSocketAddressInfoOriginatorToTarget;
  636. type <= kCipItemIdSocketAddressInfoTargetToOriginator; type++) {
  637. for(int j = 0; j < 2; j++) {
  638. if(common_packet_format_data_item->address_info_item[j].type_id == type) {
  639. EncodeSockaddrInfoItemTypeId(j,
  640. common_packet_format_data_item,
  641. outgoing_message);
  642. EncodeSockaddrInfoLength(j,
  643. common_packet_format_data_item,
  644. outgoing_message);
  645. EncapsulateIpAddress(
  646. common_packet_format_data_item->address_info_item[j].sin_port,
  647. common_packet_format_data_item->address_info_item[j].sin_addr,
  648. outgoing_message);
  649. FillNextNMessageOctetsWithValueAndMoveToNextPosition(0,
  650. 8,
  651. outgoing_message);
  652. break;
  653. }
  654. }
  655. }
  656. return kEipStatusOk;
  657. }
  658. void AssembleIOMessage(
  659. const CipCommonPacketFormatData *const common_packet_format_data_item,
  660. ENIPMessage *const outgoing_message) {
  661. AssembleLinearMessage(0, common_packet_format_data_item, outgoing_message);
  662. }