cipioconnection.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. /*******************************************************************************
  2. * Copyright (c) 2011, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. #include <string.h>
  7. #include <stdbool.h>
  8. #include "cipioconnection.h"
  9. #include "generic_networkhandler.h"
  10. #include "cipconnectionmanager.h"
  11. #include "cipassembly.h"
  12. #include "ciptcpipinterface.h"
  13. #include "cipcommon.h"
  14. #include "appcontype.h"
  15. #include "cpf.h"
  16. #include "trace.h"
  17. #include "endianconv.h"
  18. /*The port to be used per default for I/O messages on UDP.*/
  19. const int kOpenerEipIoUdpPort = 0x08AE;
  20. /* producing multicast connection have to consider the rules that apply for
  21. * application connection types.
  22. */
  23. EipStatus OpenProducingMulticastConnection(
  24. CipConnectionObject *connection_object,
  25. CipCommonPacketFormatData *common_packet_format_data);
  26. EipStatus OpenMulticastConnection(
  27. UdpCommuncationDirection direction,
  28. CipConnectionObject *connection_object,
  29. CipCommonPacketFormatData *common_packet_format_data);
  30. EipStatus OpenConsumingPointToPointConnection(
  31. CipConnectionObject *const connection_object,
  32. CipCommonPacketFormatData *const common_packet_format_data);
  33. EipStatus OpenProducingPointToPointConnection(
  34. CipConnectionObject *connection_object,
  35. CipCommonPacketFormatData *common_packet_format_data);
  36. EipUint16 HandleConfigData(CipConnectionObject *connection_object);
  37. /* Regularly close the IO connection. If it is an exclusive owner or input only
  38. * connection and in charge of the connection a new owner will be searched
  39. */
  40. void CloseIoConnection(CipConnectionObject *connection_object);
  41. void HandleIoConnectionTimeOut(CipConnectionObject *connection_object);
  42. /** @brief Send the data from the produced CIP Object of the connection via the socket of the connection object
  43. * on UDP.
  44. * @param connection_object pointer to the connection object
  45. * @return status EIP_OK .. success
  46. * EIP_ERROR .. error
  47. */
  48. EipStatus SendConnectedData(CipConnectionObject *connection_object);
  49. EipStatus HandleReceivedIoConnectionData(
  50. CipConnectionObject *connection_object,
  51. const EipUint8 *data,
  52. EipUint16 data_length);
  53. /**** Global variables ****/
  54. EipUint8 *g_config_data_buffer = NULL; /**< buffers for the config data coming with a forward open request. */
  55. unsigned int g_config_data_length = 0; /**< length of g_config_data_buffer. Initialized with 0 */
  56. EipUint32 g_run_idle_state; /**< buffer for holding the run idle information. */
  57. EipUint16 ProcessProductionInhibitTime(CipConnectionObject *io_connection_object)
  58. {
  59. if ( kConnectionObjectTransportClassTriggerProductionTriggerCyclic
  60. == ConnectionObjectGetTransportClassTriggerProductionTrigger(
  61. io_connection_object) ) {
  62. if ( 256 ==
  63. ConnectionObjectGetProductionInhibitTime(io_connection_object) ) {
  64. OPENER_TRACE_INFO("No PIT segment available\n");
  65. /* there was no PIT segment in the connection path; set PIT to one fourth of RPI */
  66. ConnectionObjectSetProductionInhibitTime(io_connection_object,
  67. ConnectionObjectGetTToORequestedPacketInterval(
  68. io_connection_object)
  69. / 4000);
  70. } else {
  71. /* If a production inhibit time is provided, it needs to be smaller than the Requested Packet Interval */
  72. if ( ConnectionObjectGetProductionInhibitTime(io_connection_object)
  73. > (ConnectionObjectGetTToORequestedPacketInterval(
  74. io_connection_object)
  75. / 1000) ) {
  76. /* see section C-1.4.3.3 */
  77. return kConnectionManagerExtendedStatusCodeRpiNotSupported; /**< RPI not supported. Extended Error code deprecated */
  78. }
  79. }
  80. }
  81. return kConnectionManagerExtendedStatusCodeSuccess;
  82. }
  83. void SetIoConnectionCallbacks(CipConnectionObject *const io_connection_object) {
  84. io_connection_object->connection_close_function = CloseIoConnection;
  85. io_connection_object->connection_timeout_function = HandleIoConnectionTimeOut;
  86. io_connection_object->connection_send_data_function = SendConnectedData;
  87. io_connection_object->connection_receive_data_function =
  88. HandleReceivedIoConnectionData;
  89. }
  90. EipUint16 SetupIoConnectionOriginatorToTargetConnectionPoint(
  91. CipConnectionObject *const io_connection_object,
  92. CipConnectionObject *const RESTRICT connection_object
  93. ) {
  94. CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
  95. CipInstance *instance = NULL;
  96. if ( NULL
  97. != ( instance =
  98. GetCipInstance(
  99. assembly_class,
  100. io_connection_object->consumed_path.instance_id) ) ) {
  101. /* consuming Connection Point is present */
  102. io_connection_object->consuming_instance = instance;
  103. io_connection_object->consumed_connection_path_length = 6;
  104. /*io_connection_object->consumed_path.class_id =
  105. io_connection_object->connection_path.class_id;
  106. io_connection_object->consumed_connection_path.instance_number =
  107. io_connection_object->connection_path.connection_point[
  108. kConnectionPointConsumer];*/
  109. io_connection_object->consumed_path.attribute_id_or_connection_point = 3;
  110. int data_size = ConnectionObjectGetOToTConnectionSize(io_connection_object);
  111. int diff_size = 0;
  112. /* an assembly object should always have an attribute 3 */
  113. CipAttributeStruct *attribute = GetCipAttribute(instance,
  114. io_connection_object->consumed_path.attribute_id_or_connection_point);
  115. OPENER_ASSERT(attribute != NULL);
  116. bool is_heartbeat = ( ( (CipByteArray *) attribute->data )->length == 0 );
  117. if ( kConnectionObjectTransportClassTriggerTransportClass1
  118. == ConnectionObjectGetTransportClassTriggerTransportClass(
  119. io_connection_object) ) {
  120. /* class 1 connection */
  121. data_size -= 2; /* remove 16-bit sequence count length */
  122. diff_size += 2;
  123. }
  124. if ( (kOpenerConsumedDataHasRunIdleHeader) && (data_size > 0)
  125. && (!is_heartbeat) ) {
  126. /* we only have an run idle header if it is not an heartbeat connection */
  127. data_size -= 4; /* remove the 4 bytes needed for run/idle header */
  128. diff_size += 4;
  129. }
  130. if ( ( (CipByteArray *) attribute->data )->length != data_size ) {
  131. /*wrong connection size */
  132. connection_object->correct_originator_to_target_size =
  133. ( (CipByteArray *) attribute->data )->length + diff_size;
  134. return kConnectionManagerExtendedStatusCodeErrorInvalidOToTConnectionSize;
  135. }
  136. } else {
  137. return kConnectionManagerExtendedStatusCodeInvalidConsumingApplicationPath;
  138. }
  139. return kConnectionManagerExtendedStatusCodeSuccess;
  140. }
  141. EipUint16 SetupIoConnectionTargetToOriginatorConnectionPoint(
  142. CipConnectionObject *const io_connection_object,
  143. CipConnectionObject *const RESTRICT connection_object
  144. ) {
  145. DoublyLinkedListNode *node = connection_list.first;
  146. while (NULL != node &&
  147. kConnectionObjectConnectionTypeMulticast ==
  148. ConnectionObjectGetTToOConnectionType(io_connection_object) ) {
  149. CipConnectionObject *iterator = node->data;
  150. if(io_connection_object->produced_path.instance_id ==
  151. iterator->produced_path.instance_id) {
  152. //Check parameters
  153. if( ConnectionObjectGetTToORequestedPacketInterval(io_connection_object)
  154. !=
  155. ConnectionObjectGetTToORequestedPacketInterval(iterator) ) {
  156. return kConnectionManagerExtendedStatusCodeErrorRpiValuesNotAcceptable;
  157. }
  158. if( ConnectionObjectGetTToOConnectionSizeType(
  159. io_connection_object) !=
  160. ConnectionObjectGetTToOConnectionSizeType(
  161. iterator) ) {
  162. return
  163. kConnectionManagerExtendedStatusCodeMismatchedTToONetworkConnectionFixVar;
  164. }
  165. if ( ConnectionObjectGetTToOPriority(io_connection_object) !=
  166. ConnectionObjectGetTToOPriority(iterator) ) {
  167. return
  168. kConnectionManagerExtendedStatusCodeMismatchedTToONetworkConnectionPriority;
  169. }
  170. if( ConnectionObjectGetTransportClassTriggerTransportClass(
  171. io_connection_object) !=
  172. ConnectionObjectGetTransportClassTriggerTransportClass(iterator) ) {
  173. return kConnectionManagerExtendedStatusCodeMismatchedTransportClass;
  174. }
  175. if( ConnectionObjectGetTransportClassTriggerProductionTrigger(
  176. io_connection_object) !=
  177. ConnectionObjectGetTransportClassTriggerProductionTrigger(iterator) )
  178. {
  179. return
  180. kConnectionManagerExtendedStatusCodeMismatchedTToOProductionTrigger;
  181. }
  182. if( ConnectionObjectGetProductionInhibitTime(io_connection_object) !=
  183. ConnectionObjectGetProductionInhibitTime(iterator) ) {
  184. return
  185. kConnectionManagerExtendedStatusCodeMismatchedTToOProductionInhibitTimeSegment;
  186. }
  187. }
  188. node = node->next;
  189. }
  190. /*setup producer side*/
  191. CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
  192. CipInstance *instance = NULL;
  193. if ( NULL
  194. != ( instance =
  195. GetCipInstance(
  196. assembly_class,
  197. io_connection_object->produced_path.instance_id) ) ) {
  198. io_connection_object->producing_instance = instance;
  199. int data_size = ConnectionObjectGetTToOConnectionSize(io_connection_object);
  200. int diff_size = 0;
  201. /* an assembly object should always have an attribute 3 */
  202. io_connection_object->produced_path.attribute_id_or_connection_point = 3;
  203. CipAttributeStruct *attribute = GetCipAttribute(instance,
  204. io_connection_object->produced_path.attribute_id_or_connection_point);
  205. OPENER_ASSERT(attribute != NULL);
  206. bool is_heartbeat = ( ( (CipByteArray *) attribute->data )->length == 0 );
  207. if ( kConnectionObjectTransportClassTriggerTransportClass1 ==
  208. ConnectionObjectGetTransportClassTriggerTransportClass(
  209. io_connection_object) ) {
  210. /* class 1 connection */
  211. data_size -= 2; /* remove 16-bit sequence count length */
  212. diff_size += 2;
  213. }
  214. if ( (kOpenerProducedDataHasRunIdleHeader) && (data_size > 0)
  215. && (!is_heartbeat) ) {
  216. /* we only have an run idle header if it is not an heartbeat connection */
  217. data_size -= 4; /* remove the 4 bytes needed for run/idle header */
  218. diff_size += 4;
  219. }
  220. if ( ( (CipByteArray *) attribute->data )->length != data_size ) {
  221. /*wrong connection size*/
  222. connection_object->correct_target_to_originator_size =
  223. ( (CipByteArray *) attribute->data )->length + diff_size;
  224. return kConnectionManagerExtendedStatusCodeErrorInvalidTToOConnectionSize;
  225. }
  226. } else {
  227. return kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath;
  228. }
  229. return kConnectionManagerExtendedStatusCodeSuccess;
  230. }
  231. /** @brief Establishes a new IO Type 1 Connection
  232. *
  233. * This function needs the guarantee that no Null request will be passed to it.
  234. * It will generate a new IO connection based on the data parsed in the Forward Open service
  235. *
  236. * @param connection_object pointer to the connection object structure holding the parsed data from the forward open request
  237. * @param extended_error the extended error code in case an error happened
  238. * @return general status on the establishment
  239. * - kEipStatusOk ... on success
  240. * - On an error the general status code to be put into the response
  241. */
  242. EipStatus EstablishIoConnection(
  243. CipConnectionObject *RESTRICT const connection_object,
  244. EipUint16 *const extended_error
  245. ) {
  246. EipStatus eip_status = kEipStatusOk;
  247. CipConnectionObject *io_connection_object = GetIoConnectionForConnectionData(
  248. connection_object,
  249. extended_error);
  250. if(NULL == io_connection_object) {
  251. return kCipErrorConnectionFailure;
  252. }
  253. *extended_error = ProcessProductionInhibitTime(io_connection_object);
  254. if(0 != *extended_error) {
  255. return kCipErrorConnectionFailure;
  256. }
  257. SetIoConnectionCallbacks(io_connection_object);
  258. ConnectionObjectGeneralConfiguration(io_connection_object);
  259. ConnectionObjectConnectionType originator_to_target_connection_type =
  260. ConnectionObjectGetOToTConnectionType(io_connection_object);
  261. ConnectionObjectConnectionType target_to_originator_connection_type =
  262. ConnectionObjectGetTToOConnectionType(io_connection_object);
  263. /** Already handled by forward open */
  264. OPENER_ASSERT( !(originator_to_target_connection_type ==
  265. kConnectionObjectConnectionTypeNull &&
  266. target_to_originator_connection_type ==
  267. kConnectionObjectConnectionTypeNull) );
  268. io_connection_object->consuming_instance = NULL;
  269. io_connection_object->consumed_connection_path_length = 0;
  270. io_connection_object->producing_instance = NULL;
  271. io_connection_object->produced_connection_path_length = 0;
  272. /* we don't need to check for zero as this is handled in the connection path parsing */
  273. if (originator_to_target_connection_type !=
  274. kConnectionObjectConnectionTypeNull) { /*setup consumer side*/
  275. *extended_error = SetupIoConnectionOriginatorToTargetConnectionPoint(
  276. io_connection_object,
  277. connection_object);
  278. if (kConnectionManagerExtendedStatusCodeSuccess != *extended_error) {
  279. return kCipErrorConnectionFailure;
  280. }
  281. }
  282. if (target_to_originator_connection_type !=
  283. kConnectionObjectConnectionTypeNull) { /*setup producer side*/
  284. *extended_error = SetupIoConnectionTargetToOriginatorConnectionPoint(
  285. io_connection_object,
  286. connection_object);
  287. if (kConnectionManagerExtendedStatusCodeSuccess != *extended_error) {
  288. return kCipErrorConnectionFailure;
  289. }
  290. }
  291. if (NULL != g_config_data_buffer) { /* config data has been sent with this forward open request */
  292. *extended_error = HandleConfigData(io_connection_object);
  293. if (kConnectionManagerExtendedStatusCodeSuccess != *extended_error) {
  294. return kCipErrorConnectionFailure;
  295. }
  296. }
  297. eip_status = OpenCommunicationChannels(io_connection_object);
  298. if (kEipStatusOk != eip_status) {
  299. *extended_error = 0; /*TODO find out the correct extended error code*/
  300. return eip_status;
  301. }
  302. AddNewActiveConnection(io_connection_object);
  303. CheckIoConnectionEvent(
  304. io_connection_object->consumed_path.instance_id,
  305. io_connection_object->produced_path.instance_id,
  306. kIoConnectionEventOpened);
  307. return eip_status;
  308. }
  309. /** @brief Open a Point2Point connection dependent on pa_direction.
  310. *
  311. * @param connection_object Pointer to registered Object in ConnectionManager.
  312. * @param common_packet_format_data Index of the connection object
  313. * @return kEipStatusOk on success, otherwise kEipStatusError
  314. */
  315. EipStatus OpenConsumingPointToPointConnection(
  316. CipConnectionObject *const connection_object,
  317. CipCommonPacketFormatData *const common_packet_format_data
  318. ) {
  319. int j = 0;
  320. if (common_packet_format_data->address_info_item[0].type_id == 0) { /* it is not used yet */
  321. j = 0;
  322. } else if (common_packet_format_data->address_info_item[1].type_id == 0) {
  323. j = 1;
  324. }
  325. struct sockaddr_in addr =
  326. { .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(
  327. kOpenerEipIoUdpPort) };
  328. CipUsint qos_for_socket = ConnectionObjectGetTToOPriority(connection_object);
  329. int socket = CreateUdpSocket(kUdpCommuncationDirectionConsuming,
  330. &addr,
  331. qos_for_socket); /* the address is only needed for bind used if consuming */
  332. if (socket == kEipInvalidSocket) {
  333. OPENER_TRACE_ERR(
  334. "cannot create UDP socket in OpenPointToPointConnection\n");
  335. return kEipStatusError;
  336. }
  337. connection_object->originator_address = addr; /* store the address of the originator for packet scanning */
  338. addr.sin_addr.s_addr = INADDR_ANY; /* restore the address */
  339. connection_object->socket[kUdpCommuncationDirectionConsuming] = socket;
  340. common_packet_format_data->address_info_item[j].length = 16;
  341. common_packet_format_data->address_info_item[j].type_id =
  342. kCipItemIdSocketAddressInfoOriginatorToTarget;
  343. common_packet_format_data->address_info_item[j].sin_port = addr.sin_port;
  344. /*TODO should we add our own address here? */
  345. common_packet_format_data->address_info_item[j].sin_addr = addr.sin_addr
  346. .s_addr;
  347. memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
  348. common_packet_format_data->address_info_item[j].sin_family = htons(AF_INET);
  349. return kEipStatusOk;
  350. }
  351. EipStatus OpenProducingPointToPointConnection(
  352. CipConnectionObject *connection_object,
  353. CipCommonPacketFormatData *common_packet_format_data
  354. ) {
  355. in_port_t port = htons(kOpenerEipIoUdpPort); /* the default port to be used if no port information is part of the forward open request */
  356. if (kCipItemIdSocketAddressInfoTargetToOriginator
  357. == common_packet_format_data->address_info_item[0].type_id) {
  358. port = common_packet_format_data->address_info_item[0].sin_port;
  359. } else {
  360. if (kCipItemIdSocketAddressInfoTargetToOriginator
  361. == common_packet_format_data->address_info_item[1].type_id) {
  362. port = common_packet_format_data->address_info_item[1].sin_port;
  363. }
  364. }
  365. connection_object->remote_address.sin_family = AF_INET;
  366. connection_object->remote_address.sin_addr.s_addr = 0; /* we don't know the address of the originate will be set in the IApp_CreateUDPSocket */
  367. connection_object->remote_address.sin_port = port;
  368. CipUsint qos_for_socket = ConnectionObjectGetTToOPriority(connection_object);
  369. int socket = CreateUdpSocket(kUdpCommuncationDirectionProducing,
  370. &connection_object->remote_address,
  371. qos_for_socket); /* the address is only needed for bind used if consuming */
  372. if (socket == kEipInvalidSocket) {
  373. OPENER_TRACE_ERR(
  374. "cannot create UDP socket in OpenPointToPointConnection\n");
  375. /* *pa_pnExtendedError = 0x0315; miscellaneous*/
  376. return kCipErrorConnectionFailure;
  377. }
  378. connection_object->socket[kUdpCommuncationDirectionProducing] = socket;
  379. return kEipStatusOk;
  380. }
  381. EipStatus OpenProducingMulticastConnection(
  382. CipConnectionObject *connection_object,
  383. CipCommonPacketFormatData *common_packet_format_data
  384. ) {
  385. CipConnectionObject *existing_connection_object =
  386. GetExistingProducerMulticastConnection(
  387. connection_object->produced_path.instance_id);
  388. int j = 0; /* allocate an unused sockaddr struct to use */
  389. if (g_common_packet_format_data_item.address_info_item[0].type_id == 0) { /* it is not used yet */
  390. j = 0;
  391. } else if (g_common_packet_format_data_item.address_info_item[1].type_id
  392. == 0) {
  393. j = 1;
  394. }
  395. common_packet_format_data->address_info_item[j].type_id =
  396. kCipItemIdSocketAddressInfoTargetToOriginator;
  397. if (NULL == existing_connection_object) { /* we are the first connection producing for the given Input Assembly */
  398. return OpenMulticastConnection(kUdpCommuncationDirectionProducing,
  399. connection_object,
  400. common_packet_format_data);
  401. } else {
  402. /* we need to inform our originator on the correct connection id */
  403. connection_object->cip_produced_connection_id = existing_connection_object
  404. ->
  405. cip_produced_connection_id;
  406. }
  407. /* we have a connection reuse the data and the socket */
  408. if (kConnectionObjectInstanceTypeIOExclusiveOwner ==
  409. connection_object->instance_type) {
  410. /* exclusive owners take the socket and further manage the connection
  411. * especially in the case of time outs.
  412. */
  413. connection_object->socket[kUdpCommuncationDirectionProducing] =
  414. existing_connection_object->socket[kUdpCommuncationDirectionProducing];
  415. existing_connection_object->socket[kUdpCommuncationDirectionProducing] =
  416. kEipInvalidSocket;
  417. } else { /* this connection will not produce the data */
  418. connection_object->socket[kUdpCommuncationDirectionProducing] =
  419. kEipInvalidSocket;
  420. }
  421. common_packet_format_data->address_info_item[j].length = 16;
  422. connection_object->remote_address.sin_family = AF_INET;
  423. connection_object->remote_address.sin_port = common_packet_format_data
  424. ->address_info_item[j].sin_port
  425. = htons(kOpenerEipIoUdpPort);
  426. connection_object->remote_address.sin_addr.s_addr = common_packet_format_data
  427. ->address_info_item[j].
  428. sin_addr =
  429. g_multicast_configuration
  430. .
  431. starting_multicast_address;
  432. memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
  433. common_packet_format_data->address_info_item[j].sin_family = htons(AF_INET);
  434. return kEipStatusOk;
  435. }
  436. /** @brief Open a Multicast connection dependent on @var direction.
  437. *
  438. * @param direction Flag to indicate if consuming or producing.
  439. * @param connection_object pointer to registered Object in ConnectionManager.
  440. * @param common_packet_format_data received CPF Data Item.
  441. * @return kEipStatusOk on success, otherwise kEipStatusError
  442. */
  443. EipStatus OpenMulticastConnection(
  444. UdpCommuncationDirection direction,
  445. CipConnectionObject *connection_object,
  446. CipCommonPacketFormatData *common_packet_format_data
  447. ) {
  448. int j = -1;
  449. int address_info_item_which_contains_o_to_t = -1;
  450. int address_info_item_which_contains_t_to_o = -1;
  451. if(kCipItemIdSocketAddressInfoOriginatorToTarget
  452. == common_packet_format_data->address_info_item[0].type_id) {
  453. address_info_item_which_contains_o_to_t = 0;
  454. } else if(kCipItemIdSocketAddressInfoOriginatorToTarget
  455. == common_packet_format_data->address_info_item[1].type_id) {
  456. address_info_item_which_contains_o_to_t = 1;
  457. } else {
  458. OPENER_TRACE_INFO("No O->T Sockaddr info available\n");
  459. }
  460. if(kCipItemIdSocketAddressInfoTargetToOriginator
  461. == common_packet_format_data->address_info_item[0].type_id) {
  462. address_info_item_which_contains_t_to_o = 0;
  463. } else if(kCipItemIdSocketAddressInfoTargetToOriginator
  464. == common_packet_format_data->address_info_item[1].type_id) {
  465. address_info_item_which_contains_t_to_o = 1;
  466. } else {
  467. OPENER_TRACE_INFO("No T->O Sockaddr info available\n");
  468. }
  469. if(kUdpCommuncationDirectionConsuming == direction) {
  470. //OPENER_ASSERT(-1 != address_info_item_which_contains_o_to_t);
  471. j = address_info_item_which_contains_o_to_t;
  472. }
  473. if(kUdpCommuncationDirectionProducing == direction) {
  474. //OPENER_ASSERT(-1 != address_info_item_which_contains_o_to_t);
  475. j = address_info_item_which_contains_t_to_o;
  476. }
  477. /*****************/
  478. if (-1 == j) {
  479. OPENER_TRACE_ERR(
  480. "no suitable addr info item available / O->T: %d, T->O: %d, Selector: %d, direction: %d\n",
  481. address_info_item_which_contains_o_to_t,
  482. address_info_item_which_contains_t_to_o,
  483. j,
  484. direction);
  485. return kEipStatusError;
  486. }
  487. if (kCipItemIdSocketAddressInfoTargetToOriginator ==
  488. common_packet_format_data->address_info_item[j].type_id) { /* we are using an unused item initialize it with the default multicast address */
  489. common_packet_format_data->address_info_item[j].sin_family = htons(
  490. AF_INET);
  491. common_packet_format_data->address_info_item[j].sin_port = htons(
  492. kOpenerEipIoUdpPort);
  493. common_packet_format_data->address_info_item[j].sin_addr =
  494. g_multicast_configuration.starting_multicast_address;
  495. memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
  496. common_packet_format_data->address_info_item[j].length = 16;
  497. }
  498. if (htons(AF_INET)
  499. != common_packet_format_data->address_info_item[j].sin_family) {
  500. OPENER_TRACE_ERR(
  501. "Sockaddr Info Item with wrong sin family value received\n");
  502. return kEipStatusError;
  503. }
  504. /* allocate an unused sockaddr struct to use */
  505. struct sockaddr_in socket_address = {0};
  506. socket_address.sin_family = ntohs(
  507. common_packet_format_data->address_info_item[j].sin_family);
  508. socket_address.sin_addr.s_addr =
  509. common_packet_format_data->address_info_item[j].sin_addr;
  510. socket_address.sin_port = common_packet_format_data->address_info_item[j]
  511. .sin_port;
  512. CipUsint qos_for_socket = ConnectionObjectGetTToOPriority(connection_object);
  513. int socket = CreateUdpSocket(direction, &socket_address, qos_for_socket); /* the address is only needed for bind used if consuming */
  514. if (socket == kEipInvalidSocket) {
  515. OPENER_TRACE_ERR("cannot create UDP socket in OpenMulticastConnection\n");
  516. return kEipStatusError;
  517. }
  518. connection_object->socket[direction] = socket;
  519. if (direction == kUdpCommuncationDirectionConsuming) {
  520. common_packet_format_data->address_info_item[j].type_id =
  521. kCipItemIdSocketAddressInfoOriginatorToTarget;
  522. connection_object->originator_address = socket_address;
  523. } else {
  524. common_packet_format_data->address_info_item[j].type_id =
  525. kCipItemIdSocketAddressInfoTargetToOriginator;
  526. connection_object->remote_address = socket_address;
  527. }
  528. return kEipStatusOk;
  529. }
  530. EipUint16 HandleConfigData(CipConnectionObject *connection_object) {
  531. CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
  532. EipUint16 connection_manager_status = 0;
  533. CipInstance *config_instance = GetCipInstance(
  534. assembly_class, connection_object->configuration_path.instance_id);
  535. if (0 != g_config_data_length) {
  536. if ( ConnectionWithSameConfigPointExists(
  537. connection_object->configuration_path.instance_id) ) { /* there is a connected connection with the same config point
  538. * we have to have the same data as already present in the config point*/
  539. CipByteArray *attribute_three = (CipByteArray *) GetCipAttribute(
  540. config_instance,
  541. 3)->data;
  542. if (attribute_three->length != g_config_data_length) {
  543. connection_manager_status =
  544. kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
  545. OPENER_TRACE_INFO(
  546. "Hit an Ownership conflict in cipioconnection.c occurrence 1");
  547. } else {
  548. /*FIXME check if this is correct */
  549. if ( memcmp(attribute_three->data, g_config_data_buffer,
  550. g_config_data_length) ) {
  551. connection_manager_status =
  552. kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
  553. OPENER_TRACE_INFO(
  554. "Hit an Ownership conflict in cipioconnection.c occurrence 2");
  555. }
  556. }
  557. } else {
  558. /* put the data on the configuration assembly object with the current
  559. design this can be done rather efficiently */
  560. if ( kEipStatusOk
  561. != NotifyAssemblyConnectedDataReceived(config_instance,
  562. g_config_data_buffer,
  563. g_config_data_length) ) {
  564. OPENER_TRACE_WARN("Configuration data was invalid\n");
  565. connection_manager_status =
  566. kConnectionManagerExtendedStatusCodeInvalidConfigurationApplicationPath;
  567. }
  568. }
  569. }
  570. return connection_manager_status;
  571. }
  572. void CloseIoConnection(CipConnectionObject *connection_object) {
  573. CheckIoConnectionEvent(connection_object->consumed_path.instance_id,
  574. connection_object->produced_path.instance_id,
  575. kIoConnectionEventClosed);
  576. if ( kConnectionObjectInstanceTypeIOExclusiveOwner ==
  577. ConnectionObjectGetInstanceType(connection_object)
  578. || kConnectionObjectInstanceTypeIOInputOnly ==
  579. ConnectionObjectGetInstanceType(connection_object) ) {
  580. if ( ( kConnectionObjectConnectionTypeMulticast
  581. == ConnectionObjectGetTToOConnectionType(connection_object) )
  582. && (kEipInvalidSocket
  583. != connection_object->socket[kUdpCommuncationDirectionProducing]) )
  584. {
  585. CipConnectionObject *next_non_control_master_connection =
  586. GetNextNonControlMasterConnection(
  587. connection_object->produced_path.instance_id);
  588. if (NULL != next_non_control_master_connection) {
  589. /* Transfer socket ownership */
  590. next_non_control_master_connection->socket[
  591. kUdpCommuncationDirectionProducing] =
  592. connection_object->socket[kUdpCommuncationDirectionProducing];
  593. connection_object->socket[kUdpCommuncationDirectionProducing] =
  594. kEipInvalidSocket;
  595. /* End */
  596. memcpy( &(next_non_control_master_connection->remote_address),
  597. &(connection_object->remote_address),
  598. sizeof(next_non_control_master_connection->remote_address) );
  599. next_non_control_master_connection->eip_level_sequence_count_producing
  600. =
  601. connection_object->eip_level_sequence_count_producing;
  602. next_non_control_master_connection->sequence_count_producing =
  603. connection_object->sequence_count_producing;
  604. next_non_control_master_connection->transmission_trigger_timer =
  605. connection_object->transmission_trigger_timer;
  606. } else { /* this was the last master connection close all listen only connections listening on the port */
  607. CloseAllConnectionsForInputWithSameType(
  608. connection_object->produced_path.instance_id,
  609. kConnectionObjectInstanceTypeIOListenOnly);
  610. }
  611. }
  612. }
  613. CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
  614. connection_object);
  615. }
  616. void HandleIoConnectionTimeOut(CipConnectionObject *connection_object) {
  617. CheckIoConnectionEvent(connection_object->produced_path.instance_id,
  618. connection_object->consumed_path.instance_id,
  619. kIoConnectionEventTimedOut);
  620. if ( kConnectionObjectConnectionTypeMulticast
  621. == ConnectionObjectGetTToOConnectionType(connection_object) ) {
  622. switch (ConnectionObjectGetInstanceType(connection_object) ) {
  623. case kConnectionObjectInstanceTypeIOExclusiveOwner:
  624. CloseAllConnectionsForInputWithSameType(
  625. connection_object->produced_path.instance_id,
  626. kConnectionObjectInstanceTypeIOInputOnly);
  627. CloseAllConnectionsForInputWithSameType(
  628. connection_object->produced_path.instance_id,
  629. kConnectionObjectInstanceTypeIOListenOnly);
  630. break;
  631. case kConnectionObjectInstanceTypeIOInputOnly:
  632. if (kEipInvalidSocket
  633. != connection_object->socket[kUdpCommuncationDirectionProducing]) { /* we are the controlling input only connection find a new controller*/
  634. CipConnectionObject *next_non_control_master_connection =
  635. GetNextNonControlMasterConnection(
  636. connection_object->produced_path.instance_id);
  637. if (NULL != next_non_control_master_connection) {
  638. next_non_control_master_connection->socket[
  639. kUdpCommuncationDirectionProducing] =
  640. connection_object->socket[kUdpCommuncationDirectionProducing];
  641. connection_object->socket[kUdpCommuncationDirectionProducing] =
  642. kEipInvalidSocket;
  643. next_non_control_master_connection->transmission_trigger_timer =
  644. connection_object->transmission_trigger_timer;
  645. } else { /* this was the last master connection close all listen only connections listening on the port */
  646. CloseAllConnectionsForInputWithSameType(
  647. connection_object->produced_path.instance_id,
  648. kConnectionObjectInstanceTypeIOListenOnly);
  649. }
  650. }
  651. break;
  652. default:
  653. break;
  654. }
  655. }
  656. ConnectionObjectSetState(connection_object, kConnectionObjectStateTimedOut);
  657. // OPENER_ASSERT(NULL != connection_object->connection_close_function);
  658. // connection_object->connection_close_function(connection_object);
  659. }
  660. EipStatus SendConnectedData(CipConnectionObject *connection_object) {
  661. /* TODO think of adding an own send buffer to each connection object in order to preset up the whole message on connection opening and just change the variable data items e.g., sequence number */
  662. CipCommonPacketFormatData *common_packet_format_data =
  663. &g_common_packet_format_data_item; /* TODO think on adding a CPF data item to the S_CIP_ConnectionObject in order to remove the code here or even better allocate memory in the connection object for storing the message to send and just change the application data*/
  664. connection_object->eip_level_sequence_count_producing++;
  665. /* assembleCPFData */
  666. common_packet_format_data->item_count = 2;
  667. if ( kConnectionObjectTransportClassTriggerTransportClass0 !=
  668. ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
  669. { /* use Sequenced Address Items if not Connection Class 0 */
  670. common_packet_format_data->address_item.type_id =
  671. kCipItemIdSequencedAddressItem;
  672. common_packet_format_data->address_item.length = 8;
  673. common_packet_format_data->address_item.data.sequence_number =
  674. connection_object->eip_level_sequence_count_producing;
  675. } else {
  676. common_packet_format_data->address_item.type_id =
  677. kCipItemIdConnectionAddress;
  678. common_packet_format_data->address_item.length = 4;
  679. }
  680. common_packet_format_data->address_item.data.connection_identifier =
  681. connection_object->cip_produced_connection_id;
  682. common_packet_format_data->data_item.type_id = kCipItemIdConnectedDataItem;
  683. CipByteArray *producing_instance_attributes =
  684. (CipByteArray *) connection_object->producing_instance->attributes->data;
  685. common_packet_format_data->data_item.length = 0;
  686. /* notify the application that data will be sent immediately after the call */
  687. if ( BeforeAssemblyDataSend(connection_object->producing_instance) ) {
  688. /* the data has changed increase sequence counter */
  689. connection_object->sequence_count_producing++;
  690. }
  691. /* set AddressInfo Items to invalid Type */
  692. common_packet_format_data->address_info_item[0].type_id = 0;
  693. common_packet_format_data->address_info_item[1].type_id = 0;
  694. EipUint16 reply_length = AssembleIOMessage(common_packet_format_data,
  695. &g_message_data_reply_buffer[0]);
  696. EipUint8 *message_data_reply_buffer =
  697. &g_message_data_reply_buffer[reply_length - 2];
  698. common_packet_format_data->data_item.length = producing_instance_attributes
  699. ->length;
  700. if (kOpenerProducedDataHasRunIdleHeader) {
  701. common_packet_format_data->data_item.length += 4;
  702. }
  703. if (kConnectionObjectTransportClassTriggerTransportClass1 ==
  704. ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
  705. {
  706. common_packet_format_data->data_item.length += 2;
  707. AddIntToMessage(common_packet_format_data->data_item.length,
  708. &message_data_reply_buffer);
  709. AddIntToMessage(connection_object->sequence_count_producing,
  710. &message_data_reply_buffer);
  711. } else {
  712. AddIntToMessage(common_packet_format_data->data_item.length,
  713. &message_data_reply_buffer);
  714. }
  715. if (kOpenerProducedDataHasRunIdleHeader) {
  716. AddDintToMessage( g_run_idle_state, &(message_data_reply_buffer) );
  717. }
  718. memcpy(message_data_reply_buffer, producing_instance_attributes->data,
  719. producing_instance_attributes->length);
  720. reply_length += common_packet_format_data->data_item.length;
  721. return SendUdpData(
  722. &connection_object->remote_address,
  723. connection_object->socket[kUdpCommuncationDirectionProducing],
  724. &g_message_data_reply_buffer[0], reply_length);
  725. }
  726. EipStatus HandleReceivedIoConnectionData(
  727. CipConnectionObject *connection_object,
  728. const EipUint8 *data,
  729. EipUint16 data_length
  730. ) {
  731. /* check class 1 sequence number*/
  732. if (kConnectionObjectTransportClassTriggerTransportClass1 ==
  733. ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
  734. {
  735. EipUint16 sequence_buffer = GetIntFromMessage( &(data) );
  736. if ( SEQ_LEQ16(sequence_buffer,
  737. connection_object->sequence_count_consuming) ) {
  738. return kEipStatusOk; /* no new data for the assembly */
  739. }
  740. connection_object->sequence_count_consuming = sequence_buffer;
  741. data_length -= 2;
  742. }
  743. if (data_length > 0) {
  744. /* we have no heartbeat connection */
  745. if (kOpenerConsumedDataHasRunIdleHeader) {
  746. EipUint32 nRunIdleBuf = GetDintFromMessage( &(data) );
  747. if (g_run_idle_state != nRunIdleBuf) {
  748. RunIdleChanged(nRunIdleBuf);
  749. }
  750. g_run_idle_state = nRunIdleBuf;
  751. data_length -= 4;
  752. }
  753. if (NotifyAssemblyConnectedDataReceived(
  754. connection_object->consuming_instance, (EipUint8 *const)data,
  755. data_length) != 0) {
  756. return kEipStatusError;
  757. }
  758. }
  759. return kEipStatusOk;
  760. }
  761. EipStatus OpenCommunicationChannels(CipConnectionObject *connection_object) {
  762. EipStatus eip_status = kEipStatusOk;
  763. /*get pointer to the CPF data, currently we have just one global instance of the struct. This may change in the future*/
  764. CipCommonPacketFormatData *common_packet_format_data =
  765. &g_common_packet_format_data_item;
  766. ConnectionObjectConnectionType originator_to_target_connection_type =
  767. ConnectionObjectGetOToTConnectionType(connection_object);
  768. ConnectionObjectConnectionType target_to_originator_connection_type =
  769. ConnectionObjectGetTToOConnectionType(connection_object);
  770. /* open a connection "point to point" or "multicast" based on the ConnectionParameter */
  771. if (originator_to_target_connection_type ==
  772. kConnectionObjectConnectionTypeMulticast) /* Multicast consuming */
  773. {
  774. if (OpenMulticastConnection(kUdpCommuncationDirectionConsuming,
  775. connection_object, common_packet_format_data)
  776. == kEipStatusError) {
  777. OPENER_TRACE_ERR("error in OpenMulticast Connection\n");
  778. return kCipErrorConnectionFailure;
  779. }
  780. } else if (originator_to_target_connection_type ==
  781. kConnectionObjectConnectionTypePointToPoint) /* Point to Point consuming */
  782. {
  783. if (OpenConsumingPointToPointConnection(connection_object,
  784. common_packet_format_data)
  785. == kEipStatusError) {
  786. OPENER_TRACE_ERR("error in PointToPoint consuming connection\n");
  787. return kCipErrorConnectionFailure;
  788. }
  789. }
  790. if (target_to_originator_connection_type ==
  791. kConnectionObjectConnectionTypeMulticast) /* Multicast producing */
  792. {
  793. if (OpenProducingMulticastConnection(connection_object,
  794. common_packet_format_data)
  795. == kEipStatusError) {
  796. OPENER_TRACE_ERR("error in OpenMulticast Connection\n");
  797. return kCipErrorConnectionFailure;
  798. }
  799. } else if (target_to_originator_connection_type ==
  800. kConnectionObjectConnectionTypePointToPoint) /* Point to Point producing */
  801. {
  802. if (OpenProducingPointToPointConnection(connection_object,
  803. common_packet_format_data)
  804. != kEipStatusOk) {
  805. OPENER_TRACE_ERR("error in PointToPoint producing connection\n");
  806. return kCipErrorConnectionFailure;
  807. }
  808. }
  809. return eip_status;
  810. }
  811. void CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
  812. CipConnectionObject *connection_object) {
  813. CloseUdpSocket(
  814. connection_object->socket[kUdpCommuncationDirectionConsuming]);
  815. connection_object->socket[kUdpCommuncationDirectionConsuming] =
  816. kEipInvalidSocket;
  817. CloseUdpSocket(
  818. connection_object->socket[kUdpCommuncationDirectionProducing]);
  819. connection_object->socket[kUdpCommuncationDirectionProducing] =
  820. kEipInvalidSocket;
  821. RemoveFromActiveConnections(connection_object);
  822. ConnectionObjectInitializeEmpty(connection_object);
  823. }