cipconnectionobject.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. /*******************************************************************************
  2. * Copyright (c) 2017, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. #include <string.h>
  7. #include "cipconnectionobject.h"
  8. #include "endianconv.h"
  9. #include "trace.h"
  10. #include "cipconnectionmanager.h"
  11. #define CIP_CONNECTION_OBJECT_STATE_NON_EXISTENT 0U
  12. #define CIP_CONNECTION_OBJECT_STATE_CONFIGURING 1U
  13. #define CIP_CONNECTION_OBJECT_STATE_WAITING_FOR_CONNECTION_ID 2U
  14. #define CIP_CONNECTION_OBJECT_STATE_ESTABLISHED 3U
  15. #define CIP_CONNECTION_OBJECT_STATE_TIMEOUT 4U
  16. #define CIP_CONNECTION_OBJECT_STATE_DEFERRED_DELETE 5U
  17. #define CIP_CONNECTION_OBJECT_STATE_CLOSING 6U
  18. #define CIP_CONNECTION_OBJECT_INSTANCE_TYPE_EXPLICIT_MESSAGING 0
  19. #define CIP_CONNECTION_OBJECT_INSTANCE_TYPE_IO 1
  20. #define CIP_CONNECTION_OBJECT_INSTANCE_TYPE_CIP_BRIDGED 2
  21. #define CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_CYCLIC ( \
  22. 0 << 4)
  23. #define \
  24. CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_CHANGE_OF_STATE ( \
  25. 1 << 4)
  26. #define \
  27. CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_APPLICATION_OBJECT ( \
  28. 2 << 4)
  29. #define CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_0 0
  30. #define CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_1 1
  31. #define CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_2 2
  32. #define CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_3 3
  33. #define CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_TRANSITION_TO_TIMED_OUT 0
  34. #define CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_DELETE 1
  35. #define CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_RESET 2
  36. #define CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_DEFERRED_DELETE 3
  37. #define CIP_CONNECTION_OBJECT_CONNECTION_TYPE_NULL 0
  38. #define CIP_CONNECTION_OBJECT_CONNECTION_TYPE_MULTICAST (1 << 13)
  39. #define CIP_CONNECTION_OBJECT_CONNECTION_TYPE_POINT_TO_POINT (1 << 14)
  40. #define CIP_CONNECTION_OBJECT_PRIORITY_LOW 0
  41. #define CIP_CONNECTION_OBJECT_PRIORITY_HIGH (1 << 10)
  42. #define CIP_CONNECTION_OBJECT_PRIORITY_SCHEDULED (1 << 11)
  43. #define CIP_CONNECTION_OBJECT_PRIORITY_URGENT (3 << 10)
  44. DoublyLinkedList connection_list;
  45. /** @brief Array of the available explicit connections */
  46. CipConnectionObject explicit_connection_object_pool[
  47. OPENER_CIP_NUM_EXPLICIT_CONNS];
  48. DoublyLinkedListNode *CipConnectionObjectListArrayAllocator() {
  49. enum {kNodesAmount = OPENER_CIP_NUM_EXPLICIT_CONNS +
  50. OPENER_CIP_NUM_INPUT_ONLY_CONNS +
  51. OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS +
  52. OPENER_CIP_NUM_LISTEN_ONLY_CONNS};
  53. static DoublyLinkedListNode nodes[kNodesAmount] = {0};
  54. for(size_t i = 0; i < kNodesAmount; ++i) {
  55. if(nodes[i].previous == NULL && nodes[i].next == NULL && nodes[i].data ==
  56. NULL) {
  57. return &nodes[i];
  58. }
  59. }
  60. return NULL;
  61. }
  62. void CipConnectionObjectListArrayFree(DoublyLinkedListNode **node) {
  63. if(NULL != node) {
  64. if(NULL != *node) {
  65. memset( *node, 0, sizeof(DoublyLinkedListNode) );
  66. *node = NULL;
  67. } else {
  68. OPENER_TRACE_ERR("Attempt to delete NULL pointer to node\n");
  69. }
  70. OPENER_TRACE_ERR("Attempt to provide a NULL pointer to node pointer\n");
  71. }
  72. }
  73. /* Private methods declaration */
  74. uint64_t ConnectionObjectCalculateRegularInactivityWatchdogTimerValue(
  75. const CipConnectionObject *const connection_object);
  76. void ConnectionObjectSetInitialInactivityWatchdogTimerValue(
  77. CipConnectionObject *const connection_object);
  78. /* End private methods declaration */
  79. void ConnectionObjectInitializeEmpty(
  80. CipConnectionObject *const connection_object) {
  81. memset( connection_object, 0, sizeof(*connection_object) );
  82. ConnectionObjectSetState(connection_object,
  83. kConnectionObjectStateNonExistent);
  84. connection_object->socket[0] = kEipInvalidSocket;
  85. connection_object->socket[1] = kEipInvalidSocket;
  86. }
  87. CipConnectionObject *CipConnectionObjectCreate(const CipOctet *message) {
  88. assert(false); /* NOT IMLEMENTED */
  89. return NULL;
  90. }
  91. void ConnectionObjectInitializeFromMessage(
  92. const CipOctet **message,
  93. CipConnectionObject *const connection_object) {
  94. /* For unconnected send - can be ignored by targets, and is ignored here */
  95. CipByte priority_timetick = GetSintFromMessage(message);
  96. CipUsint timeout_ticks = GetSintFromMessage(message);
  97. /* O_to_T Conn ID */
  98. ConnectionObjectSetCipConsumedConnectionID(connection_object,
  99. GetDintFromMessage(message) );
  100. /* T_to_O Conn ID */
  101. ConnectionObjectSetCipProducedConnectionID(connection_object,
  102. GetDintFromMessage(message) );
  103. ConnectionObjectSetConnectionSerialNumber(connection_object,
  104. GetIntFromMessage(message) );
  105. ConnectionObjectSetOriginatorVendorId(connection_object,
  106. GetIntFromMessage(message) );
  107. ConnectionObjectSetOriginatorSerialNumber(connection_object,
  108. GetDintFromMessage(message) );
  109. /* keep it to none existent till the setup is done this eases error handling and
  110. * the state changes within the forward open request can not be detected from
  111. * the application or from outside (reason we are single threaded)
  112. * */
  113. ConnectionObjectSetState(connection_object,
  114. kConnectionObjectStateNonExistent);
  115. connection_object->sequence_count_producing = 0; /* set the sequence count to zero */
  116. ConnectionObjectSetConnectionTimeoutMultiplier(connection_object,
  117. GetSintFromMessage(
  118. message) );
  119. MoveMessageNOctets(3, message); /* 3 bytes reserved */
  120. /* the requested packet interval parameter needs to be a multiple of TIMERTICK from the header file */
  121. OPENER_TRACE_INFO(
  122. "ForwardOpen: ConConnID %" PRIu32 ", ProdConnID %" PRIu32
  123. ", ConnSerNo %u\n",
  124. connection_object->cip_consumed_connection_id,
  125. connection_object->cip_produced_connection_id,
  126. connection_object->connection_serial_number);
  127. ConnectionObjectSetOToTRequestedPacketInterval(connection_object,
  128. GetDintFromMessage(
  129. message) );
  130. ConnectionObjectSetInitialInactivityWatchdogTimerValue(connection_object);
  131. //TODO: introduce setter function
  132. connection_object->o_to_t_network_connection_parameters = GetIntFromMessage(
  133. message);
  134. ConnectionObjectSetTToORequestedPacketInterval(connection_object,
  135. GetDintFromMessage(message) );
  136. ConnectionObjectSetExpectedPacketRate(connection_object);
  137. connection_object->t_to_o_network_connection_parameters = GetIntFromMessage(
  138. message);
  139. connection_object->transport_class_trigger = GetSintFromMessage(message);
  140. }
  141. ConnectionObjectState ConnectionObjectGetState(
  142. const CipConnectionObject *const connection_object) {
  143. ConnectionObjectState new_state = kConnectionObjectStateInvalid;
  144. switch (connection_object->state) {
  145. case CIP_CONNECTION_OBJECT_STATE_NON_EXISTENT:
  146. new_state = kConnectionObjectStateNonExistent;
  147. break;
  148. case CIP_CONNECTION_OBJECT_STATE_CONFIGURING:
  149. new_state = kConnectionObjectStateConfiguring;
  150. break;
  151. case CIP_CONNECTION_OBJECT_STATE_WAITING_FOR_CONNECTION_ID:
  152. new_state = kConnectionObjectStateWaitingForConnectionID;
  153. break;
  154. case CIP_CONNECTION_OBJECT_STATE_ESTABLISHED:
  155. new_state = kConnectionObjectStateEstablished;
  156. break;
  157. case CIP_CONNECTION_OBJECT_STATE_TIMEOUT:
  158. new_state = kConnectionObjectStateTimedOut;
  159. break;
  160. case CIP_CONNECTION_OBJECT_STATE_DEFERRED_DELETE:
  161. new_state = kConnectionObjectStateDeferredDelete;
  162. break;
  163. case CIP_CONNECTION_OBJECT_STATE_CLOSING:
  164. new_state = kConnectionObjectStateClosing;
  165. break;
  166. default:
  167. new_state = kConnectionObjectStateInvalid;
  168. break;
  169. }
  170. return new_state;
  171. }
  172. void ConnectionObjectSetState(CipConnectionObject *const connection_object,
  173. const ConnectionObjectState state) {
  174. switch (state) {
  175. case kConnectionObjectStateNonExistent:
  176. connection_object->state =
  177. CIP_CONNECTION_OBJECT_STATE_NON_EXISTENT;
  178. break;
  179. case kConnectionObjectStateConfiguring:
  180. connection_object->state =
  181. CIP_CONNECTION_OBJECT_STATE_CONFIGURING;
  182. break;
  183. case kConnectionObjectStateWaitingForConnectionID:
  184. connection_object->state =
  185. CIP_CONNECTION_OBJECT_STATE_WAITING_FOR_CONNECTION_ID;
  186. break;
  187. case kConnectionObjectStateEstablished:
  188. connection_object->state =
  189. CIP_CONNECTION_OBJECT_STATE_ESTABLISHED;
  190. break;
  191. case kConnectionObjectStateTimedOut:
  192. connection_object->state =
  193. CIP_CONNECTION_OBJECT_STATE_TIMEOUT;
  194. break;
  195. case kConnectionObjectStateDeferredDelete:
  196. connection_object->state =
  197. CIP_CONNECTION_OBJECT_STATE_DEFERRED_DELETE;
  198. break;
  199. case kConnectionObjectStateClosing:
  200. connection_object->state =
  201. CIP_CONNECTION_OBJECT_STATE_CLOSING;
  202. break;
  203. default:
  204. OPENER_ASSERT(false) /* Never get here */
  205. break;
  206. }
  207. }
  208. ConnectionObjectInstanceType ConnectionObjectGetInstanceType(
  209. const CipConnectionObject *const connection_object) {
  210. return connection_object->instance_type;
  211. // switch (connection_object->instance_type) {
  212. // case CIP_CONNECTION_OBJECT_INSTANCE_TYPE_EXPLICIT_MESSAGING:
  213. // return kConnectionObjectInstanceTypeExplicitMessaging;
  214. // break;
  215. // case CIP_CONNECTION_OBJECT_INSTANCE_TYPE_IO:
  216. // return kConnectionObjectInstanceTypeIO;
  217. // break;
  218. // case CIP_CONNECTION_OBJECT_INSTANCE_TYPE_CIP_BRIDGED:
  219. // return kConnectionObjectInstanceTypeCipBridged;
  220. // break;
  221. // default:
  222. // return kConnectionObjectInstanceTypeInvalid;
  223. // }
  224. }
  225. void ConnectionObjectSetInstanceType(
  226. CipConnectionObject *const connection_object,
  227. const ConnectionObjectInstanceType instance_type) {
  228. connection_object->instance_type = instance_type;
  229. }
  230. CipUsint ConnectionObjectGetInstanceTypeForAttribute(
  231. const CipConnectionObject *const connection_object) {
  232. CipUsint instance_type = kConnectionObjectInstanceTypeInvalid;
  233. switch (connection_object->instance_type) {
  234. case kConnectionObjectInstanceTypeExplicitMessaging:
  235. instance_type = CIP_CONNECTION_OBJECT_INSTANCE_TYPE_EXPLICIT_MESSAGING;
  236. break;
  237. case kConnectionObjectInstanceTypeIO:
  238. case kConnectionObjectInstanceTypeIOExclusiveOwner:
  239. case kConnectionObjectInstanceTypeIOInputOnly:
  240. case kConnectionObjectInstanceTypeIOListenOnly:
  241. instance_type = CIP_CONNECTION_OBJECT_INSTANCE_TYPE_IO;
  242. break;
  243. case kConnectionObjectInstanceTypeCipBridged:
  244. instance_type = CIP_CONNECTION_OBJECT_INSTANCE_TYPE_CIP_BRIDGED;
  245. break;
  246. default:
  247. OPENER_ASSERT(false) /* This is a fault case */
  248. instance_type = kConnectionObjectInstanceTypeInvalid;
  249. break;
  250. }
  251. return instance_type;
  252. }
  253. bool ConnectionObjectIsTypeNonLOIOConnection(
  254. const CipConnectionObject *const connection_object) {
  255. switch(connection_object->instance_type) {
  256. case kConnectionObjectInstanceTypeIO:
  257. case kConnectionObjectInstanceTypeIOExclusiveOwner:
  258. case kConnectionObjectInstanceTypeIOInputOnly:
  259. return true;
  260. default: return false;
  261. }
  262. return false;
  263. }
  264. bool ConnectionObjectIsTypeIOConnection(
  265. const CipConnectionObject *const connection_object) {
  266. switch(connection_object->instance_type) {
  267. case kConnectionObjectInstanceTypeIO:
  268. case kConnectionObjectInstanceTypeIOExclusiveOwner:
  269. case kConnectionObjectInstanceTypeIOInputOnly:
  270. case kConnectionObjectInstanceTypeIOListenOnly:
  271. return true;
  272. default: return false;
  273. }
  274. return false;
  275. }
  276. ConnectionObjectTransportClassTriggerDirection
  277. ConnectionObjectGetTransportClassTriggerDirection(
  278. const CipConnectionObject *const connection_object) {
  279. const CipByte TransportClassTriggerDirectionMask = 0x80;
  280. return (connection_object->transport_class_trigger &
  281. TransportClassTriggerDirectionMask) ==
  282. TransportClassTriggerDirectionMask ?
  283. kConnectionObjectTransportClassTriggerDirectionServer
  284. : kConnectionObjectTransportClassTriggerDirectionClient;
  285. }
  286. ConnectionObjectTransportClassTriggerProductionTrigger
  287. ConnectionObjectGetTransportClassTriggerProductionTrigger(
  288. const CipConnectionObject *const connection_object) {
  289. const CipByte kTransportClassTriggerProductionTriggerMask = 0x70;
  290. ConnectionObjectTransportClassTriggerProductionTrigger production_trigger =
  291. kConnectionObjectTransportClassTriggerProductionTriggerInvalid;
  292. switch ( (connection_object->transport_class_trigger) &
  293. kTransportClassTriggerProductionTriggerMask ) {
  294. case
  295. CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_CYCLIC:
  296. production_trigger =
  297. kConnectionObjectTransportClassTriggerProductionTriggerCyclic;
  298. break;
  299. case
  300. CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_CHANGE_OF_STATE
  301. :
  302. production_trigger =
  303. kConnectionObjectTransportClassTriggerProductionTriggerChangeOfState;
  304. break;
  305. case
  306. CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_APPLICATION_OBJECT
  307. :
  308. production_trigger =
  309. kConnectionObjectTransportClassTriggerProductionTriggerApplicationObject;
  310. break;
  311. default:
  312. production_trigger =
  313. kConnectionObjectTransportClassTriggerProductionTriggerInvalid;
  314. break;
  315. }
  316. return production_trigger;
  317. }
  318. ConnectionObjectTransportClassTriggerTransportClass
  319. ConnectionObjectGetTransportClassTriggerTransportClass(
  320. const CipConnectionObject *const connection_object) {
  321. const CipByte kTransportClassTriggerTransportClassMask = 0x0F;
  322. ConnectionObjectTransportClassTriggerTransportClass transport_class_trigger =
  323. kConnectionObjectTransportClassTriggerTransportClassInvalid;
  324. switch ( (connection_object->transport_class_trigger) &
  325. kTransportClassTriggerTransportClassMask ) {
  326. case CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_0:
  327. transport_class_trigger =
  328. kConnectionObjectTransportClassTriggerTransportClass0;
  329. break;
  330. case CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_1:
  331. transport_class_trigger =
  332. kConnectionObjectTransportClassTriggerTransportClass1;
  333. break;
  334. case CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_2:
  335. transport_class_trigger =
  336. kConnectionObjectTransportClassTriggerTransportClass2;
  337. break;
  338. case CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_3:
  339. transport_class_trigger =
  340. kConnectionObjectTransportClassTriggerTransportClass3;
  341. break;
  342. default:
  343. transport_class_trigger =
  344. kConnectionObjectTransportClassTriggerTransportClassInvalid;
  345. }
  346. return transport_class_trigger;
  347. }
  348. CipUint ConnectionObjectGetProducedConnectionSize(
  349. const CipConnectionObject *const connection_object) {
  350. return connection_object->produced_connection_size;
  351. }
  352. void ConnectionObjectSetProducedConnectionSize(
  353. CipConnectionObject *const connection_object,
  354. const CipUint
  355. produced_connection_size) {
  356. connection_object->produced_connection_size = produced_connection_size;
  357. }
  358. CipUint ConnectionObjectGetConsumedConnectionSize(
  359. const CipConnectionObject *const connection_object) {
  360. return connection_object->consumed_connection_size;
  361. }
  362. void ConnectionObjectSetConsumedConnectionSize(
  363. CipConnectionObject *const connection_object,
  364. const CipUint consumed_connection_size) {
  365. connection_object->consumed_connection_size = consumed_connection_size;
  366. }
  367. CipUint ConnectionObjectGetExpectedPacketRate(
  368. const CipConnectionObject *const connection_object) {
  369. return connection_object->expected_packet_rate;
  370. }
  371. CipUint ConnectionObjectGetRequestedPacketInterval(
  372. const CipConnectionObject *const connection_object) {
  373. CipUdint remainder_to_resolution =
  374. (connection_object->t_to_o_requested_packet_interval) %
  375. (kOpenerTimerTickInMilliSeconds * 1000);
  376. if( 0 == remainder_to_resolution ) { /* Value can be represented in multiples of the timer resolution */
  377. return (CipUint)(connection_object->t_to_o_requested_packet_interval /
  378. 1000);
  379. }
  380. else{
  381. return (CipUint)(connection_object->t_to_o_requested_packet_interval /
  382. 1000 - remainder_to_resolution / 1000);
  383. }
  384. }
  385. void ConnectionObjectSetExpectedPacketRate(
  386. CipConnectionObject *const connection_object) {
  387. CipUdint remainder_to_resolution =
  388. (connection_object->t_to_o_requested_packet_interval) %
  389. (kOpenerTimerTickInMilliSeconds * 1000);
  390. if( 0 == remainder_to_resolution ) { /* Value can be represented in multiples of the timer resolution */
  391. connection_object->expected_packet_rate =
  392. connection_object->t_to_o_requested_packet_interval / 1000;
  393. }
  394. else{
  395. connection_object->expected_packet_rate =
  396. connection_object->t_to_o_requested_packet_interval / 1000 +
  397. ( (CipUdint)
  398. kOpenerTimerTickInMilliSeconds - remainder_to_resolution / 1000 );
  399. }
  400. }
  401. CipUdint ConnectionObjectGetCipProducedConnectionID(
  402. const CipConnectionObject *const connection_object) {
  403. return connection_object->cip_produced_connection_id;
  404. }
  405. void ConnectionObjectSetCipProducedConnectionID(
  406. CipConnectionObject *const connection_object,
  407. const CipUdint
  408. cip_produced_connection_id) {
  409. connection_object->cip_produced_connection_id = cip_produced_connection_id;
  410. }
  411. CipUdint ConnectionObjectGetCipConsumedConnectionID(
  412. const CipConnectionObject *const connection_object) {
  413. return connection_object->cip_consumed_connection_id;
  414. }
  415. void ConnectionObjectSetCipConsumedConnectionID(
  416. CipConnectionObject *const connection_object,
  417. const CipUdint
  418. cip_consumed_connection_id) {
  419. connection_object->cip_consumed_connection_id = cip_consumed_connection_id;
  420. }
  421. ConnectionObjectWatchdogTimeoutAction ConnectionObjectGetWatchdogTimeoutAction(
  422. const CipConnectionObject *const connection_object) {
  423. ConnectionObjectWatchdogTimeoutAction timeout_action =
  424. kConnectionObjectWatchdogTimeoutActionInvalid;
  425. switch (connection_object->watchdog_timeout_action) {
  426. case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_TRANSITION_TO_TIMED_OUT:
  427. timeout_action =
  428. kConnectionObjectWatchdogTimeoutActionTransitionToTimedOut;
  429. break;
  430. case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_DELETE:
  431. timeout_action = kConnectionObjectWatchdogTimeoutActionAutoDelete;
  432. break;
  433. case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_RESET:
  434. timeout_action = kConnectionObjectWatchdogTimeoutActionAutoReset;
  435. break;
  436. case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_DEFERRED_DELETE:
  437. timeout_action = kConnectionObjectWatchdogTimeoutActionDeferredDelete;
  438. break;
  439. default:
  440. timeout_action = kConnectionObjectWatchdogTimeoutActionInvalid;
  441. break;
  442. }
  443. return timeout_action;
  444. }
  445. void ConnectionObjectSetWatchdogTimeoutAction(
  446. CipConnectionObject *const connection_object,
  447. const CipUsint
  448. watchdog_timeout_action) {
  449. switch (watchdog_timeout_action) {
  450. case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_TRANSITION_TO_TIMED_OUT:
  451. connection_object->watchdog_timeout_action =
  452. kConnectionObjectWatchdogTimeoutActionTransitionToTimedOut;
  453. break;
  454. case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_DELETE:
  455. connection_object->watchdog_timeout_action =
  456. kConnectionObjectWatchdogTimeoutActionAutoDelete;
  457. break;
  458. case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_RESET:
  459. connection_object->watchdog_timeout_action =
  460. kConnectionObjectWatchdogTimeoutActionAutoReset;
  461. break;
  462. case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_DEFERRED_DELETE:
  463. connection_object->watchdog_timeout_action =
  464. kConnectionObjectWatchdogTimeoutActionDeferredDelete;
  465. break;
  466. default:
  467. connection_object->watchdog_timeout_action =
  468. kConnectionObjectWatchdogTimeoutActionInvalid;
  469. break;
  470. }
  471. }
  472. CipUint ConnectionObjectGetProducedConnectionPathLength(
  473. const CipConnectionObject *const connection_object) {
  474. return connection_object->produced_connection_path_length;
  475. }
  476. void ConnectionObjectSetProducedConnectionPathLength(
  477. CipConnectionObject *const connection_object,
  478. const CipUint
  479. produced_connection_path_length) {
  480. connection_object->produced_connection_path_length =
  481. produced_connection_path_length;
  482. }
  483. CipUint ConnectionObjectGetConsumedConnectionPathLength(
  484. const CipConnectionObject *const connection_object) {
  485. return connection_object->consumed_connection_path_length;
  486. }
  487. void ConnectionObjectSetConsumedConnectionPathLength(
  488. CipConnectionObject *const connection_object,
  489. const CipUint
  490. consumed_connection_path_length) {
  491. connection_object->consumed_connection_path_length =
  492. consumed_connection_path_length;
  493. }
  494. CipUint ConnectionObjectGetProductionInhibitTime(
  495. const CipConnectionObject *const connection_object) {
  496. return connection_object->production_inhibit_time;
  497. }
  498. void ConnectionObjectSetProductionInhibitTime(
  499. CipConnectionObject *const connection_object,
  500. const CipUint
  501. production_inhibit_time) {
  502. connection_object->production_inhibit_time = production_inhibit_time;
  503. }
  504. /*setup the preconsumption timer: max(ConnectionTimeoutMultiplier * ExpectedPacketRate, 10s) */
  505. void ConnectionObjectSetInitialInactivityWatchdogTimerValue(
  506. CipConnectionObject *const connection_object) {
  507. const uint64_t kMinimumInitialTimeoutValue = 10000;
  508. const uint64_t calculated_timeout_value =
  509. ConnectionObjectCalculateRegularInactivityWatchdogTimerValue(
  510. connection_object);
  511. connection_object->inactivity_watchdog_timer =
  512. (calculated_timeout_value >
  513. kMinimumInitialTimeoutValue) ? calculated_timeout_value :
  514. kMinimumInitialTimeoutValue;
  515. }
  516. void ConnectionObjectResetInactivityWatchdogTimerValue(
  517. CipConnectionObject *const connection_object) {
  518. connection_object->inactivity_watchdog_timer =
  519. ConnectionObjectCalculateRegularInactivityWatchdogTimerValue(
  520. connection_object);
  521. }
  522. void ConnectionObjectResetLastPackageInactivityTimerValue(
  523. CipConnectionObject *const connection_object) {
  524. connection_object->last_package_watchdog_timer =
  525. ConnectionObjectCalculateRegularInactivityWatchdogTimerValue(
  526. connection_object);
  527. }
  528. uint64_t ConnectionObjectCalculateRegularInactivityWatchdogTimerValue(
  529. const CipConnectionObject *const connection_object) {
  530. return ( ( (uint64_t)(connection_object->o_to_t_requested_packet_interval) /
  531. (uint64_t)1000 ) <<
  532. (2 + connection_object->connection_timeout_multiplier) );
  533. }
  534. CipUint ConnectionObjectGetConnectionSerialNumber(
  535. const CipConnectionObject *const connection_object) {
  536. return connection_object->connection_serial_number;
  537. }
  538. void ConnectionObjectSetConnectionSerialNumber(
  539. CipConnectionObject *connection_object,
  540. const CipUint connection_serial_number) {
  541. connection_object->connection_serial_number = connection_serial_number;
  542. }
  543. CipUint ConnectionObjectGetOriginatorVendorId(
  544. const CipConnectionObject *const connection_object) {
  545. return connection_object->originator_vendor_id;
  546. }
  547. void ConnectionObjectSetOriginatorVendorId(
  548. CipConnectionObject *connection_object,
  549. const CipUint vendor_id) {
  550. connection_object->originator_vendor_id = vendor_id;
  551. }
  552. CipUdint ConnectionObjectGetOriginatorSerialNumber(
  553. const CipConnectionObject *const connection_object) {
  554. return connection_object->originator_serial_number;
  555. }
  556. void ConnectionObjectSetOriginatorSerialNumber(
  557. CipConnectionObject *connection_object,
  558. CipUdint originator_serial_number) {
  559. connection_object->originator_serial_number = originator_serial_number;
  560. }
  561. CipUsint ConnectionObjectGetConnectionTimeoutMultiplier(
  562. const CipConnectionObject *const connection_object) {
  563. return connection_object->connection_timeout_multiplier;
  564. }
  565. void ConnectionObjectSetConnectionTimeoutMultiplier(
  566. CipConnectionObject *connection_object,
  567. CipUsint connection_timeout_multiplier) {
  568. connection_object->connection_timeout_multiplier =
  569. connection_timeout_multiplier;
  570. }
  571. CipUdint ConnectionObjectGetOToTRequestedPacketInterval(
  572. const CipConnectionObject *const connection_object) {
  573. return connection_object->o_to_t_requested_packet_interval;
  574. }
  575. void ConnectionObjectSetOToTRequestedPacketInterval(
  576. CipConnectionObject *connection_object,
  577. const CipUdint requested_packet_interval) {
  578. connection_object->o_to_t_requested_packet_interval =
  579. requested_packet_interval;
  580. }
  581. CipUdint ConnectionObjectGetTToORequestedPacketInterval(
  582. const CipConnectionObject *const connection_object) {
  583. return connection_object->t_to_o_requested_packet_interval;
  584. }
  585. void ConnectionObjectSetTToORequestedPacketInterval(
  586. CipConnectionObject *connection_object,
  587. const CipUdint requested_packet_interval) {
  588. connection_object->t_to_o_requested_packet_interval =
  589. requested_packet_interval;
  590. }
  591. bool ConnectionObjectIsOToTRedundantOwner(
  592. const CipConnectionObject *const connection_object) {
  593. const CipWord kOwnerMask = 0x80;
  594. return kOwnerMask & connection_object->o_to_t_network_connection_parameters;
  595. }
  596. bool ConnectionObjectIsTToORedundantOwner(
  597. const CipConnectionObject *const connection_object) {
  598. const CipWord kOwnerMask = 0x80;
  599. return kOwnerMask & connection_object->t_to_o_network_connection_parameters;
  600. }
  601. ConnectionObjectConnectionType ConnectionObjectGetConnectionType(
  602. const CipWord connection_parameters) {
  603. const CipWord kConnectionTypeMask = 3 << 13;
  604. switch(connection_parameters & kConnectionTypeMask) {
  605. case CIP_CONNECTION_OBJECT_CONNECTION_TYPE_NULL: return
  606. kConnectionObjectConnectionTypeNull;
  607. case CIP_CONNECTION_OBJECT_CONNECTION_TYPE_MULTICAST: return
  608. kConnectionObjectConnectionTypeMulticast;
  609. case CIP_CONNECTION_OBJECT_CONNECTION_TYPE_POINT_TO_POINT: return
  610. kConnectionObjectConnectionTypePointToPoint;
  611. default: return kConnectionObjectConnectionTypeInvalid;
  612. }
  613. }
  614. ConnectionObjectConnectionType ConnectionObjectGetOToTConnectionType(
  615. const CipConnectionObject *const connection_object) {
  616. return ConnectionObjectGetConnectionType(
  617. connection_object->o_to_t_network_connection_parameters);
  618. }
  619. ConnectionObjectConnectionType ConnectionObjectGetTToOConnectionType(
  620. const CipConnectionObject *const connection_object) {
  621. return ConnectionObjectGetConnectionType(
  622. connection_object->t_to_o_network_connection_parameters);
  623. }
  624. ConnectionObjectPriority ConnectionObjectGetPriority(
  625. const CipWord connection_parameters) {
  626. const CipWord kPriorityMask = 3 << 10;
  627. ConnectionObjectPriority result;
  628. switch(connection_parameters & kPriorityMask) {
  629. case CIP_CONNECTION_OBJECT_PRIORITY_LOW: result =
  630. kConnectionObjectPriorityLow; break;
  631. case CIP_CONNECTION_OBJECT_PRIORITY_HIGH: result =
  632. kConnectionObjectPriorityHigh; break;
  633. case CIP_CONNECTION_OBJECT_PRIORITY_SCHEDULED: result =
  634. kConnectionObjectPriorityScheduled; break;
  635. case CIP_CONNECTION_OBJECT_PRIORITY_URGENT: result =
  636. kConnectionObjectPriorityUrgent; break;
  637. default: OPENER_ASSERT(false) /* Not possible to get here! */
  638. result = kConnectionObjectPriorityLow;
  639. break;
  640. }
  641. return result;
  642. }
  643. ConnectionObjectPriority ConnectionObjectGetOToTPriority(
  644. const CipConnectionObject *const connection_object) {
  645. return ConnectionObjectGetPriority(
  646. connection_object->o_to_t_network_connection_parameters);
  647. }
  648. ConnectionObjectPriority ConnectionObjectGetTToOPriority(
  649. const CipConnectionObject *const connection_object) {
  650. return ConnectionObjectGetPriority(
  651. connection_object->t_to_o_network_connection_parameters);
  652. }
  653. ConnectionObjectConnectionSizeType ConnectionObjectGetConnectionSizeType(
  654. const CipWord connection_parameters) {
  655. const CipWord kConnectionSizeTypeMask = 1 << 9;
  656. if(connection_parameters & kConnectionSizeTypeMask) {
  657. return kConnectionObjectConnectionSizeTypeVariable;
  658. } else {
  659. return kConnectionObjectConnectionSizeTypeFixed;
  660. }
  661. }
  662. ConnectionObjectConnectionSizeType ConnectionObjectGetOToTConnectionSizeType(
  663. const CipConnectionObject *const connection_object) {
  664. return ConnectionObjectGetConnectionSizeType(
  665. connection_object->o_to_t_network_connection_parameters);
  666. }
  667. ConnectionObjectConnectionSizeType ConnectionObjectGetTToOConnectionSizeType(
  668. const CipConnectionObject *const connection_object) {
  669. return ConnectionObjectGetConnectionSizeType(
  670. connection_object->t_to_o_network_connection_parameters);
  671. }
  672. size_t ConnectionObjectGetConnectionSize(const CipWord connection_parameters) {
  673. const CipWord kConnectionSizeMask = 0x01FF;
  674. return connection_parameters & kConnectionSizeMask;
  675. }
  676. size_t ConnectionObjectGetOToTConnectionSize(
  677. const CipConnectionObject *const connection_object) {
  678. return ConnectionObjectGetConnectionSize(
  679. connection_object->o_to_t_network_connection_parameters);
  680. }
  681. size_t ConnectionObjectGetTToOConnectionSize(
  682. const CipConnectionObject *const connection_object) {
  683. return ConnectionObjectGetConnectionSize(
  684. connection_object->t_to_o_network_connection_parameters);
  685. }
  686. void ConnectionObjectDeepCopy(
  687. CipConnectionObject *RESTRICT destination,
  688. const CipConnectionObject *RESTRICT const source
  689. ) {
  690. memcpy( destination, source, sizeof(CipConnectionObject) );
  691. }
  692. void ConnectionObjectResetSequenceCounts(
  693. CipConnectionObject *const connection_object) {
  694. connection_object->eip_level_sequence_count_producing = 0;
  695. connection_object->sequence_count_producing = 0;
  696. connection_object->eip_level_sequence_count_consuming = 0;
  697. connection_object->sequence_count_consuming = 0;
  698. }
  699. void ConnectionObjectResetProductionInhibitTimer(
  700. CipConnectionObject *const connection_object) {
  701. connection_object->production_inhibit_timer =
  702. connection_object->production_inhibit_time;
  703. }
  704. void ConnectionObjectGeneralConfiguration(
  705. CipConnectionObject *const connection_object) {
  706. connection_object->socket[0] = kEipInvalidSocket;
  707. connection_object->socket[1] = kEipInvalidSocket;
  708. if ( kConnectionObjectConnectionTypePointToPoint
  709. == ConnectionObjectGetOToTConnectionType(connection_object) ) {
  710. /* if we have a point to point connection for the O to T direction
  711. * the target shall choose the connection ID.
  712. */
  713. ConnectionObjectSetCipConsumedConnectionID(connection_object,
  714. GetConnectionId() );
  715. }
  716. if ( kConnectionObjectConnectionTypeMulticast
  717. == ConnectionObjectGetTToOConnectionType(connection_object) ) {
  718. /* if we have a multi-cast connection for the T to O direction the
  719. * target shall choose the connection ID.
  720. */
  721. ConnectionObjectSetCipProducedConnectionID(connection_object,
  722. GetConnectionId() );
  723. }
  724. ConnectionObjectResetSequenceCounts(connection_object);
  725. ConnectionObjectSetWatchdogTimeoutAction(connection_object,
  726. kConnectionObjectWatchdogTimeoutActionInvalid); /* Correct value not know at this point */
  727. ConnectionObjectResetProductionInhibitTimer(connection_object);
  728. connection_object->transmission_trigger_timer = 0;
  729. }
  730. bool ConnectionObjectEqualOriginator(const CipConnectionObject *const object1,
  731. const CipConnectionObject *const object2) {
  732. if ( (object1->originator_vendor_id
  733. == object2->originator_vendor_id)
  734. && (object1->originator_serial_number
  735. == object2->originator_serial_number) ) {
  736. return true;
  737. }
  738. return false;
  739. }
  740. bool EqualConnectionTriad(const CipConnectionObject *const object1,
  741. const CipConnectionObject *const object2) {
  742. if ( (object1->connection_serial_number
  743. == object2->connection_serial_number)
  744. && (object1->originator_vendor_id
  745. == object2->originator_vendor_id)
  746. && (object1->originator_serial_number
  747. == object2->originator_serial_number) ) {
  748. return true;
  749. }
  750. return false;
  751. }
  752. bool CipConnectionObjectOriginatorHasSameIP(
  753. const CipConnectionObject *const connection_object,
  754. const struct sockaddr *const originator_address) {
  755. return ( (struct sockaddr_in *) originator_address )->sin_addr.s_addr ==
  756. connection_object->originator_address.sin_addr.s_addr;
  757. }