cipconnectionobject.c 35 KB

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