cipconnectionmanager.c 79 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829
  1. /*******************************************************************************
  2. * Copyright (c) 2009, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. #include <string.h>
  7. #include <stdbool.h>
  8. #include "cipconnectionmanager.h"
  9. #include "opener_user_conf.h"
  10. #include "cipcommon.h"
  11. #include "cipmessagerouter.h"
  12. #include "ciperror.h"
  13. #include "endianconv.h"
  14. #include "opener_api.h"
  15. #include "encap.h"
  16. #include "cipidentity.h"
  17. #include "trace.h"
  18. #include "cipconnectionobject.h"
  19. #include "cipclass3connection.h"
  20. #include "cipioconnection.h"
  21. #include "cipassembly.h"
  22. #include "cpf.h"
  23. #include "appcontype.h"
  24. #include "generic_networkhandler.h"
  25. #include "cipepath.h"
  26. #include "cipelectronickey.h"
  27. #include "cipqos.h"
  28. #include "xorshiftrandom.h"
  29. const size_t g_kForwardOpenHeaderLength = 36; /**< the length in bytes of the forward open command specific data till the start of the connection path (including con path size)*/
  30. const size_t g_kLargeForwardOpenHeaderLength = 40; /**< the length in bytes of the large forward open command specific data till the start of the connection path (including con path size)*/
  31. static const unsigned int g_kNumberOfConnectableObjects = 2 +
  32. OPENER_CIP_NUM_APPLICATION_SPECIFIC_CONNECTABLE_OBJECTS;
  33. typedef struct {
  34. EipUint32 class_id;
  35. OpenConnectionFunction open_connection_function;
  36. } ConnectionManagementHandling;
  37. /* global variables private */
  38. /** List holding information on the object classes and open/close function
  39. * pointers to which connections may be established.
  40. */
  41. ConnectionManagementHandling g_connection_management_list[2 +
  42. OPENER_CIP_NUM_APPLICATION_SPECIFIC_CONNECTABLE_OBJECTS
  43. ] = {{0}};
  44. /** buffer connection object needed for forward open */
  45. CipConnectionObject g_dummy_connection_object;
  46. /** @brief Holds the connection ID's "incarnation ID" in the upper 16 bits */
  47. EipUint32 g_incarnation_id;
  48. /* private functions */
  49. EipStatus ForwardOpen(CipInstance *instance,
  50. CipMessageRouterRequest *message_router_request,
  51. CipMessageRouterResponse *message_router_response,
  52. const struct sockaddr *originator_address,
  53. const CipSessionHandle encapsulation_session);
  54. EipStatus LargeForwardOpen(CipInstance *instance,
  55. CipMessageRouterRequest *message_router_request,
  56. CipMessageRouterResponse *message_router_response,
  57. const struct sockaddr *originator_address,
  58. const CipSessionHandle encapsulation_session);
  59. EipStatus ForwardClose(CipInstance *instance,
  60. CipMessageRouterRequest *message_router_request,
  61. CipMessageRouterResponse *message_router_response,
  62. const struct sockaddr *originator_address,
  63. const CipSessionHandle encapsulation_session);
  64. EipStatus GetConnectionOwner(CipInstance *instance,
  65. CipMessageRouterRequest *message_router_request,
  66. CipMessageRouterResponse *message_router_response,
  67. const struct sockaddr *originator_address,
  68. const CipSessionHandle encapsulation_session);
  69. EipStatus GetConnectionData(CipInstance *instance,
  70. CipMessageRouterRequest *message_router_request,
  71. CipMessageRouterResponse *message_router_response,
  72. const struct sockaddr *originator_address,
  73. const CipUdint encapsulation_session);
  74. EipStatus SearchConnectionData(CipInstance *instance,
  75. CipMessageRouterRequest *message_router_request,
  76. CipMessageRouterResponse *message_router_response,
  77. const struct sockaddr *originator_address,
  78. const CipUdint encapsulation_session);
  79. void AssembleConnectionDataResponseMessage(
  80. CipMessageRouterResponse *message_router_response,
  81. CipConnectionObject *connection_object);
  82. EipStatus AssembleForwardOpenResponse(CipConnectionObject *connection_object,
  83. CipMessageRouterResponse *message_router_response,
  84. EipUint8 general_status,
  85. EipUint16 extended_status);
  86. EipStatus AssembleForwardCloseResponse(EipUint16 connection_serial_number,
  87. EipUint16 originatior_vendor_id,
  88. EipUint32 originator_serial_number,
  89. CipMessageRouterRequest *message_router_request,
  90. CipMessageRouterResponse *message_router_response,
  91. EipUint16 extended_error_code);
  92. /** @brief check if the data given in the connection object match with an already established connection
  93. *
  94. * The comparison is done according to the definitions in the CIP specification Section 3-5.5.2:
  95. * The following elements have to be equal: Vendor ID, Connection Serial Number, Originator Serial Number
  96. * @param connection_object connection object containing the comparison elements from the forward open request
  97. * @return
  98. * - NULL if no equal established connection exists
  99. * - pointer to the equal connection object
  100. */
  101. CipConnectionObject *CheckForExistingConnection(
  102. const CipConnectionObject *const connection_object);
  103. /** @brief Compare the electronic key received with a forward open request with the device's data.
  104. *
  105. * @param key_format format identifier given in the forward open request
  106. * @param key_data pointer to the electronic key data received in the forward open request
  107. * @param extended_status the extended error code in case an error happened
  108. * @return general status on the establishment
  109. * - EIP_OK ... on success
  110. * - On an error the general status code to be put into the response
  111. */
  112. EipStatus CheckElectronicKeyData(EipUint8 key_format,
  113. void *key_data,
  114. EipUint16 *extended_status);
  115. /** @brief Parse the connection path of a forward open request
  116. *
  117. * This function will take the connection object and the received data stream and parse the connection path.
  118. * @param connection_object pointer to the connection object structure for which the connection should
  119. * be established
  120. * @param message_router_request pointer to the received request structure. The position of the data stream pointer has to be at the connection length entry
  121. * @param extended_error the extended error code in case an error happened
  122. * @return general status on the establishment
  123. * - kEipStatusOk ... on success
  124. * - On an error the general status code to be put into the response
  125. */
  126. EipUint8 ParseConnectionPath(CipConnectionObject *connection_object,
  127. CipMessageRouterRequest *message_router_request,
  128. EipUint16 *extended_error);
  129. ConnectionManagementHandling *GetConnectionManagementEntry(
  130. const EipUint32 class_id);
  131. void InitializeConnectionManagerData(void);
  132. void AddNullAddressItem(
  133. CipCommonPacketFormatData *common_data_packet_format_data);
  134. /** @brief gets the padded logical path TODO: enhance documentation
  135. * @param logical_path_segment TheLogical Path Segment
  136. *
  137. * @return The padded logical path
  138. */
  139. unsigned int GetPaddedLogicalPath(const EipUint8 **logical_path_segment) {
  140. unsigned int padded_logical_path = *(*logical_path_segment)++;
  141. if( (padded_logical_path & 3) == 0 ) {
  142. padded_logical_path = *(*logical_path_segment)++;
  143. } else if( (padded_logical_path & 3) == 1 ) {
  144. (*logical_path_segment)++; /* skip pad */
  145. padded_logical_path = *(*logical_path_segment)++;
  146. padded_logical_path |= *(*logical_path_segment)++ << 8;
  147. } else {
  148. OPENER_TRACE_ERR("illegal logical path segment\n");
  149. }
  150. return padded_logical_path;
  151. }
  152. /** @brief Generate a new connection Id utilizing the Incarnation Id as
  153. * described in the EIP specs.
  154. *
  155. * A unique connectionID is formed from the boot-time-specified "incarnation ID"
  156. * and the per-new-connection connection number. The legacy default is to use
  157. * the lower 16-bit as a connection counter, incrementing for each connection.
  158. *
  159. * Some conformance tests may however fail an adapter due to the connection ID
  160. * not being random enough. To meet such requirements there is an option to
  161. * enable fully random connection IDs -- although the upper 16-bits are always
  162. * derived from the incarnation ID -- i.e., each time OpENer is started the
  163. * upper 16-bits will remain be the same.
  164. *
  165. * @return new 32-bit connection id
  166. */
  167. CipUdint GetConnectionId(void) {
  168. #ifndef OPENER_RANDOMIZE_CONNECTION_ID
  169. static CipUint connection_id = 18;
  170. connection_id++;
  171. #else
  172. CipUint connection_id = NextXorShiftUint32();
  173. #endif
  174. return (g_incarnation_id | (connection_id & 0x0000FFFF) );
  175. }
  176. void InitializeConnectionManager(CipClass *class) {
  177. CipClass *meta_class = class->class_instance.cip_class;
  178. InsertAttribute( (CipInstance *) class, 1, kCipUint, EncodeCipUint, NULL,
  179. (void *) &class->revision, kGetableSingleAndAll ); /* revision */
  180. InsertAttribute( (CipInstance *) class, 2, kCipUint, EncodeCipUint, NULL,
  181. (void *) &class->number_of_instances, kGetableSingleAndAll ); /* largest instance number */
  182. InsertAttribute( (CipInstance *) class, 3, kCipUint, EncodeCipUint, NULL,
  183. (void *) &class->number_of_instances, kGetableSingle ); /* number of instances currently existing*/
  184. InsertAttribute( (CipInstance *) class, 4, kCipUint, EncodeCipUint, NULL,
  185. (void *) &kCipUintZero, kNotSetOrGetable ); /* optional attribute list - default = 0 */
  186. InsertAttribute( (CipInstance *) class, 5, kCipUint, EncodeCipUint, NULL,
  187. (void *) &kCipUintZero, kNotSetOrGetable ); /* optional service list - default = 0 */
  188. InsertAttribute( (CipInstance *) class, 6, kCipUint, EncodeCipUint, NULL,
  189. (void *) &meta_class->highest_attribute_number,
  190. kGetableSingleAndAll ); /* max class attribute number*/
  191. InsertAttribute( (CipInstance *) class, 7, kCipUint, EncodeCipUint, NULL,
  192. (void *) &class->highest_attribute_number,
  193. kGetableSingleAndAll ); /* max instance attribute number*/
  194. InsertService(meta_class,
  195. kGetAttributeAll,
  196. &GetAttributeAll,
  197. "GetAttributeAll"); /* bind instance services to the metaclass*/
  198. InsertService(meta_class,
  199. kGetAttributeSingle,
  200. &GetAttributeSingle,
  201. "GetAttributeSingle");
  202. }
  203. EipStatus ConnectionManagerInit(EipUint16 unique_connection_id) {
  204. InitializeConnectionManagerData();
  205. CipClass *connection_manager = CreateCipClass(kCipConnectionManagerClassCode, /* class code */
  206. 0, /* # of class attributes */
  207. 7, /* # highest class attribute number*/
  208. 2, /* # of class services */
  209. 0, /* # of instance attributes */
  210. 14, /* # highest instance attribute number*/
  211. 8, /* # of instance services */
  212. 1, /* # of instances */
  213. "connection manager", /* class name */
  214. 1, /* revision */
  215. &InitializeConnectionManager); /* # function pointer for initialization*/
  216. if(connection_manager == NULL) {
  217. return kEipStatusError;
  218. }
  219. InsertService(connection_manager,
  220. kGetAttributeSingle,
  221. &GetAttributeSingle,
  222. "GetAttributeSingle");
  223. InsertService(connection_manager,
  224. kGetAttributeAll,
  225. &GetAttributeAll,
  226. "GetAttributeAll");
  227. InsertService(connection_manager, kForwardOpen, &ForwardOpen, "ForwardOpen");
  228. InsertService(connection_manager,
  229. kLargeForwardOpen,
  230. &LargeForwardOpen,
  231. "LargeForwardOpen");
  232. InsertService(connection_manager, kForwardClose, &ForwardClose,
  233. "ForwardClose");
  234. InsertService(connection_manager,
  235. kGetConnectionOwner,
  236. &GetConnectionOwner,
  237. "GetConnectionOwner");
  238. InsertService(connection_manager,
  239. kGetConnectionData,
  240. &GetConnectionData,
  241. "GetConnectionData");
  242. InsertService(connection_manager,
  243. kSearchConnectionData,
  244. &SearchConnectionData,
  245. "SearchConnectionData");
  246. g_incarnation_id = ( (EipUint32) unique_connection_id ) << 16;
  247. AddConnectableObject(kCipMessageRouterClassCode, EstablishClass3Connection);
  248. AddConnectableObject(kCipAssemblyClassCode, EstablishIoConnection);
  249. return kEipStatusOk;
  250. }
  251. EipStatus HandleReceivedConnectedData(const EipUint8 *const data,
  252. int data_length,
  253. struct sockaddr_in *from_address) {
  254. if( (CreateCommonPacketFormatStructure(data, data_length,
  255. &g_common_packet_format_data_item) ) ==
  256. kEipStatusError ) {
  257. return kEipStatusError;
  258. } else {
  259. /* check if connected address item or sequenced address item received, otherwise it is no connected message and should not be here */
  260. if( (g_common_packet_format_data_item.address_item.type_id ==
  261. kCipItemIdConnectionAddress)
  262. || (g_common_packet_format_data_item.address_item.type_id ==
  263. kCipItemIdSequencedAddressItem) ) { /* found connected address item or found sequenced address item -> for now the sequence number will be ignored */
  264. if(g_common_packet_format_data_item.data_item.type_id ==
  265. kCipItemIdConnectedDataItem) { /* connected data item received */
  266. CipConnectionObject *connection_object = GetConnectedObject(
  267. g_common_packet_format_data_item.address_item.data.connection_identifier);
  268. if(connection_object == NULL) {
  269. return kEipStatusError;
  270. }
  271. /* only handle the data if it is coming from the originator */
  272. if(connection_object->originator_address.sin_addr.s_addr ==
  273. from_address->sin_addr.s_addr) {
  274. ConnectionObjectResetLastPackageInactivityTimerValue(connection_object);
  275. if(SEQ_GT32(g_common_packet_format_data_item.address_item.data.
  276. sequence_number,
  277. connection_object->eip_level_sequence_count_consuming) ||
  278. !connection_object->eip_first_level_sequence_count_received) {
  279. /* reset the watchdog timer */
  280. ConnectionObjectResetInactivityWatchdogTimerValue(connection_object);
  281. /* only inform assembly object if the sequence counter is greater or equal */
  282. connection_object->eip_level_sequence_count_consuming =
  283. g_common_packet_format_data_item.address_item.data.sequence_number;
  284. connection_object->eip_first_level_sequence_count_received = true;
  285. if(NULL != connection_object->connection_receive_data_function) {
  286. return connection_object->connection_receive_data_function(
  287. connection_object,
  288. g_common_packet_format_data_item.data_item.data,
  289. g_common_packet_format_data_item.data_item.length);
  290. }
  291. }
  292. } else {
  293. OPENER_TRACE_WARN(
  294. "Connected Message Data Received with wrong address information\n");
  295. }
  296. }
  297. }
  298. }
  299. return kEipStatusOk;
  300. }
  301. /** @brief Function prototype for all Forward Open handle functions
  302. *
  303. */
  304. typedef EipStatus (*HandleForwardOpenRequestFunction)(CipConnectionObject *
  305. connection_object,
  306. CipInstance *instance,
  307. CipMessageRouterRequest *
  308. message_router_request,
  309. CipMessageRouterResponse *
  310. message_router_response);
  311. /** @brief Handles a Null Non Matching Forward Open Request
  312. *
  313. * Null, Non-Matching - Either ping device, or configure a device’s application,
  314. * or return General Status kCipErrorConnectionFailure and
  315. * Extended Status kConnectionManagerExtendedStatusCodeNullForwardOpenNotSupported
  316. */
  317. EipStatus HandleNullNonMatchingForwardOpenRequest(
  318. CipConnectionObject *connection_object,
  319. CipInstance *instance,
  320. CipMessageRouterRequest *message_router_request,
  321. CipMessageRouterResponse *message_router_response);
  322. EipStatus HandleNullNonMatchingForwardOpenRequest(
  323. CipConnectionObject *connection_object,
  324. CipInstance *instance,
  325. CipMessageRouterRequest *message_router_request,
  326. CipMessageRouterResponse *message_router_response) {
  327. /* Suppress unused parameter compiler warning. */
  328. (void) instance;
  329. (void) message_router_request;
  330. (void) message_router_response;
  331. OPENER_TRACE_INFO("Right now we cannot handle Null requests\n");
  332. return AssembleForwardOpenResponse(connection_object,
  333. message_router_response,
  334. kCipErrorConnectionFailure,
  335. kConnectionManagerExtendedStatusCodeNullForwardOpenNotSupported);
  336. }
  337. /** @brief Handles a Null Matching Forward Open request
  338. *
  339. * Either reconfigure a target device’s application, or
  340. * return General Status kCipErrorConnectionFailure and
  341. * Extended Status kConnectionManagerExtendedStatusCodeNullForwardOpenNotSupported
  342. */
  343. EipStatus HandleNullMatchingForwardOpenRequest(
  344. CipConnectionObject *connection_object,
  345. CipInstance *instance,
  346. CipMessageRouterRequest *message_router_request,
  347. CipMessageRouterResponse *message_router_response);
  348. EipStatus HandleNullMatchingForwardOpenRequest(
  349. CipConnectionObject *connection_object,
  350. CipInstance *instance,
  351. CipMessageRouterRequest *message_router_request,
  352. CipMessageRouterResponse *message_router_response) {
  353. /* Suppress unused parameter compiler warning. */
  354. (void) instance;
  355. (void) message_router_request;
  356. OPENER_TRACE_INFO("Right now we cannot handle Null requests\n");
  357. return AssembleForwardOpenResponse(connection_object,
  358. message_router_response,
  359. kCipErrorConnectionFailure,
  360. kConnectionManagerExtendedStatusCodeNullForwardOpenNotSupported);
  361. }
  362. /** @brief Handles a Non Null Matching Forward Open Request
  363. *
  364. * Non-Null, Matching request - Return General Status = kCipErrorConnectionFailure,
  365. * Extended Status = kConnectionManagerExtendedStatusCodeErrorConnectionInUseOrDuplicateForwardOpen
  366. */
  367. EipStatus HandleNonNullMatchingForwardOpenRequest(
  368. CipConnectionObject *connection_object,
  369. CipInstance *instance,
  370. CipMessageRouterRequest *message_router_request,
  371. CipMessageRouterResponse *message_router_response);
  372. EipStatus HandleNonNullMatchingForwardOpenRequest(
  373. CipConnectionObject *connection_object,
  374. CipInstance *instance,
  375. CipMessageRouterRequest *message_router_request,
  376. CipMessageRouterResponse *message_router_response) {
  377. /* Suppress unused parameter compiler warning. */
  378. (void) instance;
  379. (void) message_router_request;
  380. OPENER_TRACE_INFO("Right now we cannot handle reconfiguration requests\n");
  381. return AssembleForwardOpenResponse(connection_object,
  382. message_router_response,
  383. kCipErrorConnectionFailure,
  384. kConnectionManagerExtendedStatusCodeErrorConnectionInUseOrDuplicateForwardOpen);
  385. }
  386. /** @brief Handles a Non Null Non Matching Forward Open Request
  387. *
  388. * Non-Null, Non-Matching request - Establish a new connection
  389. */
  390. EipStatus HandleNonNullNonMatchingForwardOpenRequest(
  391. CipConnectionObject *connection_object,
  392. CipInstance *instance,
  393. CipMessageRouterRequest *message_router_request,
  394. CipMessageRouterResponse *message_router_response);
  395. EipStatus HandleNonNullNonMatchingForwardOpenRequest(
  396. CipConnectionObject *connection_object,
  397. CipInstance *instance,
  398. CipMessageRouterRequest *message_router_request,
  399. CipMessageRouterResponse *message_router_response) {
  400. /* Suppress unused parameter compiler warning. */
  401. (void) connection_object;
  402. (void) instance;
  403. EipUint16 connection_status = kConnectionManagerExtendedStatusCodeSuccess;
  404. /*check if the trigger type value is invalid or ok */
  405. if(kConnectionObjectTransportClassTriggerProductionTriggerInvalid ==
  406. ConnectionObjectGetTransportClassTriggerProductionTrigger(&
  407. g_dummy_connection_object) )
  408. {
  409. return AssembleForwardOpenResponse(&g_dummy_connection_object,
  410. message_router_response,
  411. kCipErrorConnectionFailure,
  412. kConnectionManagerExtendedStatusCodeErrorTransportClassAndTriggerCombinationNotSupported);
  413. }
  414. EipUint32 temp = ParseConnectionPath(&g_dummy_connection_object,
  415. message_router_request,
  416. &connection_status);
  417. if(kEipStatusOk != temp) {
  418. return AssembleForwardOpenResponse(&g_dummy_connection_object,
  419. message_router_response,
  420. temp,
  421. connection_status);
  422. }
  423. /*parsing is now finished all data is available and check now establish the connection */
  424. ConnectionManagementHandling *connection_management_entry =
  425. GetConnectionManagementEntry( /* Gets correct open connection function for the targeted object */
  426. g_dummy_connection_object.configuration_path.class_id);
  427. if(NULL != connection_management_entry) {
  428. if (NULL != connection_management_entry->open_connection_function) {
  429. temp = connection_management_entry->open_connection_function(
  430. &g_dummy_connection_object, &connection_status);
  431. } else {
  432. connection_status = kConnectionManagerExtendedStatusCodeMiscellaneous;
  433. }
  434. } else {
  435. temp = kEipStatusError;
  436. connection_status =
  437. kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
  438. }
  439. if(kEipStatusOk != temp) {
  440. OPENER_TRACE_INFO("connection manager: connect failed\n");
  441. /* in case of error the dummy objects holds all necessary information */
  442. return AssembleForwardOpenResponse(&g_dummy_connection_object,
  443. message_router_response,
  444. temp,
  445. connection_status);
  446. } else {
  447. OPENER_TRACE_INFO("connection manager: connect succeeded\n");
  448. /* in case of success the new connection is added at the head of the connection list */
  449. return AssembleForwardOpenResponse(connection_list.first->data,
  450. message_router_response,
  451. kCipErrorSuccess,
  452. 0);
  453. }
  454. }
  455. /** @brief Array of Forward Open handle function pointers
  456. *
  457. * File scope variable
  458. * The first dimension handles if the request was a non-null request (0) or a null request (1),
  459. * the second dimension handles if the request was a non-matchin (0) or matching request (1)
  460. */
  461. static const HandleForwardOpenRequestFunction
  462. handle_forward_open_request_functions[2][2] =
  463. { { HandleNonNullNonMatchingForwardOpenRequest,
  464. HandleNonNullMatchingForwardOpenRequest },
  465. { HandleNullNonMatchingForwardOpenRequest,
  466. HandleNullMatchingForwardOpenRequest } };
  467. EipStatus ForwardOpenRoutine(CipInstance *instance,
  468. CipMessageRouterRequest *message_router_request,
  469. CipMessageRouterResponse *message_router_response,
  470. const struct sockaddr *originator_address,
  471. const CipSessionHandle encapsulation_session);
  472. /** @brief Check if resources for new connection available, generate ForwardOpen Reply message.
  473. *
  474. * Large Forward Open service calls Forward Open service
  475. */
  476. EipStatus LargeForwardOpen(CipInstance *instance,
  477. CipMessageRouterRequest *message_router_request,
  478. CipMessageRouterResponse *message_router_response,
  479. const struct sockaddr *originator_address,
  480. const CipSessionHandle encapsulation_session) {
  481. g_dummy_connection_object.is_large_forward_open = true;
  482. return ForwardOpenRoutine(instance,
  483. message_router_request,
  484. message_router_response,
  485. originator_address,
  486. encapsulation_session);
  487. }
  488. /** @brief Check if resources for new connection available, generate ForwardOpen Reply message.
  489. *
  490. * Forward Open four cases
  491. * Non-Null/Not matching - open a connection
  492. * Non-Null/Matching - error
  493. * Null/Not matching - ping a device/configure
  494. * Null/Matching - reconfigure
  495. *
  496. * Null connection - both O->T and T->O connection parameter field are null
  497. * Non-Null connection - one or both O->T and T->O connection parameter field are not null
  498. * Matching - Connection Triad matches an existing connection
  499. * (Connection Serial Number, Originator Vendor ID and Originator Serial Number)
  500. *
  501. * @param instance pointer to CIP object instance
  502. * @param message_router_request pointer to Message Router Request.
  503. * @param message_router_response pointer to Message Router Response.
  504. * @param originator_address address struct of the originator as received
  505. * @param encapsulation_session associated encapsulation session of the explicit message
  506. * @return >0 .. success, 0 .. no reply to send back
  507. * -1 .. error
  508. */
  509. EipStatus ForwardOpen(CipInstance *instance,
  510. CipMessageRouterRequest *message_router_request,
  511. CipMessageRouterResponse *message_router_response,
  512. const struct sockaddr *originator_address,
  513. const CipSessionHandle encapsulation_session) {
  514. g_dummy_connection_object.is_large_forward_open = false;
  515. return ForwardOpenRoutine(instance,
  516. message_router_request,
  517. message_router_response,
  518. originator_address,
  519. encapsulation_session);
  520. }
  521. EipStatus ForwardOpenRoutine(CipInstance *instance,
  522. CipMessageRouterRequest *message_router_request,
  523. CipMessageRouterResponse *message_router_response,
  524. const struct sockaddr *originator_address,
  525. const CipSessionHandle encapsulation_session) {
  526. (void) instance; /*suppress compiler warning */
  527. bool is_null_request = false; /* 1 = Null Request, 0 = Non-Null Request */
  528. bool is_matching_request = false; /* 1 = Matching Request, 0 = Non-Matching Request */
  529. /*first check if we have already a connection with the given params */
  530. ConnectionObjectInitializeFromMessage(&(message_router_request->data),
  531. &g_dummy_connection_object);
  532. g_dummy_connection_object.associated_encapsulation_session =
  533. encapsulation_session;
  534. memcpy(&(g_dummy_connection_object.originator_address),
  535. originator_address,
  536. sizeof(g_dummy_connection_object.originator_address) );
  537. ConnectionObjectConnectionType o_to_t_connection_type =
  538. ConnectionObjectGetOToTConnectionType(&g_dummy_connection_object);
  539. ConnectionObjectConnectionType t_to_o_connection_type =
  540. ConnectionObjectGetTToOConnectionType(&g_dummy_connection_object);
  541. /* Check if both connection types are valid, otherwise send error response */
  542. if(kConnectionObjectConnectionTypeInvalid == o_to_t_connection_type) {
  543. return AssembleForwardOpenResponse(&g_dummy_connection_object,
  544. message_router_response,
  545. kCipErrorConnectionFailure,
  546. kConnectionManagerExtendedStatusCodeErrorInvalidOToTConnectionType);
  547. }
  548. if(kConnectionObjectConnectionTypeInvalid == t_to_o_connection_type) {
  549. return AssembleForwardOpenResponse(&g_dummy_connection_object,
  550. message_router_response,
  551. kCipErrorConnectionFailure,
  552. kConnectionManagerExtendedStatusCodeErrorInvalidTToOConnectionType);
  553. }
  554. if(kConnectionObjectConnectionTypeMulticast == t_to_o_connection_type) {
  555. /* for multicast, check if IP is within configured net because we send TTL 1 */
  556. CipUdint originator_ip =
  557. ( (struct sockaddr_in *) originator_address )->sin_addr.s_addr;
  558. CipUdint interface_ip = g_network_status.ip_address;
  559. CipUdint interface_mask = g_network_status.network_mask;
  560. if( (originator_ip & interface_mask) != (interface_ip & interface_mask) ) {
  561. return AssembleForwardOpenResponse(&g_dummy_connection_object,
  562. message_router_response,
  563. kCipErrorConnectionFailure,
  564. kConnectionManagerExtendedStatusCodeNotConfiguredForOffSubnetMulticast);
  565. }
  566. }
  567. /* Check if request is a Null request or a Non-Null request */
  568. if(kConnectionObjectConnectionTypeNull == o_to_t_connection_type &&
  569. kConnectionObjectConnectionTypeNull == t_to_o_connection_type) {
  570. is_null_request = true;
  571. OPENER_TRACE_INFO("We have a Null request\n");
  572. } else {
  573. is_null_request = false;
  574. OPENER_TRACE_INFO("We have a Non-Null request\n");
  575. }
  576. /* Check if we have a matching or non matching request */
  577. if(NULL != CheckForExistingConnection(&g_dummy_connection_object) ) {
  578. OPENER_TRACE_INFO("We have a Matching request\n");
  579. is_matching_request = true;
  580. } else {
  581. OPENER_TRACE_INFO("We have a Non-Matching request\n");
  582. is_matching_request = false;
  583. }
  584. HandleForwardOpenRequestFunction choosen_function =
  585. handle_forward_open_request_functions[is_null_request][is_matching_request];
  586. return choosen_function(&g_dummy_connection_object,
  587. instance,
  588. message_router_request,
  589. message_router_response);
  590. }
  591. EipStatus ForwardClose(CipInstance *instance,
  592. CipMessageRouterRequest *message_router_request,
  593. CipMessageRouterResponse *message_router_response,
  594. const struct sockaddr *originator_address,
  595. const CipSessionHandle encapsulation_session) {
  596. /*Suppress compiler warning*/
  597. (void) instance;
  598. (void) encapsulation_session;
  599. /* check connection_serial_number && originator_vendor_id && originator_serial_number if connection is established */
  600. ConnectionManagerExtendedStatusCode connection_status =
  601. kConnectionManagerExtendedStatusCodeErrorConnectionTargetConnectionNotFound;
  602. /* set AddressInfo Items to invalid TypeID to prevent assembleLinearMsg to read them */
  603. g_common_packet_format_data_item.address_info_item[0].type_id = 0;
  604. g_common_packet_format_data_item.address_info_item[1].type_id = 0;
  605. message_router_request->data += 2; /* ignore Priority/Time_tick and Time-out_ticks */
  606. EipUint16 connection_serial_number = GetUintFromMessage(
  607. &message_router_request->data);
  608. EipUint16 originator_vendor_id = GetUintFromMessage(
  609. &message_router_request->data);
  610. EipUint32 originator_serial_number = GetUdintFromMessage(
  611. &message_router_request->data);
  612. OPENER_TRACE_INFO("ForwardClose: ConnSerNo %d\n", connection_serial_number);
  613. DoublyLinkedListNode *node = connection_list.first;
  614. while(NULL != node) {
  615. /* this check should not be necessary as only established connections should be in the active connection list */
  616. CipConnectionObject *connection_object = node->data;
  617. if( (kConnectionObjectStateEstablished ==
  618. ConnectionObjectGetState(connection_object) )
  619. || (kConnectionObjectStateTimedOut ==
  620. ConnectionObjectGetState(connection_object) ) ) {
  621. if( (connection_object->connection_serial_number ==
  622. connection_serial_number) &&
  623. (connection_object->originator_vendor_id == originator_vendor_id)
  624. && (connection_object->originator_serial_number ==
  625. originator_serial_number) ) {
  626. /* found the corresponding connection object -> close it */
  627. OPENER_ASSERT(NULL != connection_object->connection_close_function);
  628. if( ( (struct sockaddr_in *) originator_address )->sin_addr.s_addr ==
  629. connection_object->originator_address.sin_addr.s_addr ) {
  630. connection_object->connection_close_function(connection_object);
  631. connection_status = kConnectionManagerExtendedStatusCodeSuccess;
  632. } else {
  633. connection_status = kConnectionManagerExtendedStatusWrongCloser;
  634. }
  635. break;
  636. }
  637. }
  638. node = node->next;
  639. }
  640. if(kConnectionManagerExtendedStatusCodeErrorConnectionTargetConnectionNotFound
  641. == connection_status) {
  642. OPENER_TRACE_INFO(
  643. "Connection not found! Requested connection tried: %u, %u, %i\n",
  644. connection_serial_number,
  645. originator_vendor_id,
  646. originator_serial_number);
  647. }
  648. return AssembleForwardCloseResponse(connection_serial_number,
  649. originator_vendor_id,
  650. originator_serial_number,
  651. message_router_request,
  652. message_router_response,
  653. connection_status);
  654. }
  655. /* TODO: Not implemented */
  656. EipStatus GetConnectionOwner(CipInstance *instance,
  657. CipMessageRouterRequest *message_router_request,
  658. CipMessageRouterResponse *message_router_response,
  659. const struct sockaddr *originator_address,
  660. const CipSessionHandle encapsulation_session) {
  661. /* suppress compiler warnings */
  662. (void) instance;
  663. (void) message_router_request;
  664. (void) message_router_response;
  665. (void) originator_address;
  666. (void) encapsulation_session;
  667. return kEipStatusOk;
  668. }
  669. EipStatus GetConnectionData(CipInstance *instance,
  670. CipMessageRouterRequest *message_router_request,
  671. CipMessageRouterResponse *message_router_response,
  672. const struct sockaddr *originator_address,
  673. const CipUdint encapsulation_session) {
  674. /* Suppress unused parameter compiler warning. */
  675. (void)instance;
  676. (void)originator_address;
  677. (void)encapsulation_session;
  678. CIPServiceCode service_code = kGetConnectionData;
  679. message_router_response->reply_service = (0x80 | service_code);
  680. //get Connection Number from request
  681. EipUint16 Connection_number =
  682. GetUintFromMessage(&message_router_request->data);
  683. OPENER_TRACE_INFO("GetConnectionData for Connection_number: %d\n",
  684. Connection_number);
  685. //search connection
  686. DoublyLinkedListNode *iterator = connection_list.first;
  687. CipConnectionObject *search_connection_object = NULL;
  688. CipConnectionObject *connection_object = NULL;
  689. while(NULL != iterator) {
  690. search_connection_object = iterator->data;
  691. if( (search_connection_object->connection_number == Connection_number) ) {
  692. connection_object = search_connection_object;
  693. break;
  694. }
  695. iterator = iterator->next;
  696. }
  697. if(NULL != connection_object) {
  698. /* assemble response message */
  699. AssembleConnectionDataResponseMessage(message_router_response,
  700. connection_object);
  701. message_router_response->general_status = kEipStatusOk;
  702. OPENER_TRACE_INFO("Connection found!\n");
  703. } else {
  704. message_router_response->general_status = kCipErrorPathDestinationUnknown;
  705. OPENER_TRACE_INFO("Connection not found!\n");
  706. }
  707. return kEipStatusOk;
  708. }
  709. EipStatus SearchConnectionData(CipInstance *instance,
  710. CipMessageRouterRequest *message_router_request,
  711. CipMessageRouterResponse *message_router_response,
  712. const struct sockaddr *originator_address,
  713. const CipUdint encapsulation_session) {
  714. /* Suppress unused parameter compiler warning. */
  715. (void)instance;
  716. (void)originator_address;
  717. (void)encapsulation_session;
  718. CIPServiceCode service_code = kSearchConnectionData;
  719. message_router_response->reply_service = (0x80 | service_code);
  720. //connection data (connection triad) from request
  721. EipUint16 Connection_serial_number = GetUintFromMessage(
  722. &message_router_request->data);
  723. EipUint16 Originator_vendor_id = GetUintFromMessage(
  724. &message_router_request->data);
  725. EipUint32 Originator_serial_number = GetUdintFromMessage(
  726. &message_router_request->data);
  727. OPENER_TRACE_INFO(
  728. "SearchConnectionData for ConnSerNo: %d, OrigVendId: %d, OrigSerNo: %i,\n",
  729. Connection_serial_number,
  730. Originator_vendor_id,
  731. Originator_serial_number);
  732. //search connection
  733. DoublyLinkedListNode *iterator = connection_list.first;
  734. CipConnectionObject *search_connection_object = NULL;
  735. CipConnectionObject *connection_object = NULL;
  736. while(NULL != iterator) {
  737. search_connection_object = iterator->data;
  738. if( (search_connection_object->connection_serial_number ==
  739. Connection_serial_number)
  740. && (search_connection_object->originator_vendor_id ==
  741. Originator_vendor_id)
  742. && (search_connection_object->originator_serial_number ==
  743. Originator_serial_number) ) {
  744. connection_object = search_connection_object;
  745. break;
  746. }
  747. iterator = iterator->next;
  748. }
  749. if(NULL != connection_object) {
  750. /* assemble response message */
  751. AssembleConnectionDataResponseMessage(message_router_response,
  752. connection_object);
  753. message_router_response->general_status = kEipStatusOk;
  754. OPENER_TRACE_INFO("Connection found!\n");
  755. } else {
  756. message_router_response->general_status = kCipErrorPathDestinationUnknown;
  757. OPENER_TRACE_INFO("Connection not found!\n");
  758. }
  759. return kEipStatusOk;
  760. }
  761. void AssembleConnectionDataResponseMessage(
  762. CipMessageRouterResponse *message_router_response,
  763. CipConnectionObject *connection_object) {
  764. // Connection number UINT
  765. AddIntToMessage(connection_object->connection_number,
  766. &message_router_response->message);
  767. // Connection state UINT
  768. AddIntToMessage(connection_object->state, &message_router_response->message);
  769. // Originator Port UINT
  770. AddIntToMessage(connection_object->originator_address.sin_port,
  771. &message_router_response->message);
  772. // Target Port UINT
  773. AddIntToMessage(connection_object->remote_address.sin_port,
  774. &message_router_response->message);
  775. // Connection Serial Number UINT
  776. AddIntToMessage(connection_object->connection_serial_number,
  777. &message_router_response->message);
  778. // Originator Vendor ID UINT
  779. AddIntToMessage(connection_object->originator_vendor_id,
  780. &message_router_response->message);
  781. // Originator Serial number UDINT
  782. AddDintToMessage(connection_object->originator_serial_number,
  783. &message_router_response->message);
  784. // Originator O->T CID UDINT
  785. AddDintToMessage(connection_object->cip_consumed_connection_id,
  786. &message_router_response->message);
  787. // Target O->T CID UDINT
  788. AddDintToMessage(connection_object->cip_consumed_connection_id,
  789. &message_router_response->message);
  790. // Connection Timeout Multiplier USINT
  791. AddSintToMessage(connection_object->connection_timeout_multiplier,
  792. &message_router_response->message);
  793. // Reserved USINT
  794. AddSintToMessage(0, &message_router_response->message);
  795. // Reserved USINT
  796. AddSintToMessage(0, &message_router_response->message);
  797. // Reserved USINT
  798. AddSintToMessage(0, &message_router_response->message);
  799. // Originator RPI O->T UDINT
  800. AddDintToMessage(connection_object->o_to_t_requested_packet_interval,
  801. &message_router_response->message);
  802. // Originator API O->T UDINT
  803. AddDintToMessage(connection_object->transmission_trigger_timer,
  804. &message_router_response->message);
  805. // Originator T->O CID UDINT
  806. AddDintToMessage(connection_object->cip_produced_connection_id,
  807. &message_router_response->message);
  808. // Target T->O CID UDINT
  809. AddDintToMessage(connection_object->cip_produced_connection_id,
  810. &message_router_response->message);
  811. // Connection Timeout Multiplier USINT
  812. AddSintToMessage(connection_object->connection_timeout_multiplier,
  813. &message_router_response->message);
  814. // Reserved USINT
  815. AddSintToMessage(0, &message_router_response->message);
  816. // Reserved USINT
  817. AddSintToMessage(0, &message_router_response->message);
  818. // Reserved USINT
  819. AddSintToMessage(0, &message_router_response->message);
  820. // Originator RPI T->O UDINT
  821. AddDintToMessage(connection_object->t_to_o_requested_packet_interval,
  822. &message_router_response->message);
  823. // Originator API T->O UDINT
  824. AddDintToMessage(connection_object->transmission_trigger_timer,
  825. &message_router_response->message);
  826. }
  827. EipStatus ManageConnections(MilliSeconds elapsed_time) {
  828. //OPENER_TRACE_INFO("Entering ManageConnections\n");
  829. /*Inform application that it can execute */
  830. HandleApplication();
  831. ManageEncapsulationMessages(elapsed_time);
  832. DoublyLinkedListNode *node = connection_list.first;
  833. while(NULL != node) {
  834. //OPENER_TRACE_INFO("Entering Connection Object loop\n");
  835. CipConnectionObject *connection_object = node->data;
  836. if(kConnectionObjectStateEstablished ==
  837. ConnectionObjectGetState(connection_object) ) {
  838. if( (NULL != connection_object->consuming_instance) || /* we have a consuming connection check inactivity watchdog timer */
  839. (kConnectionObjectTransportClassTriggerDirectionServer ==
  840. ConnectionObjectGetTransportClassTriggerDirection(connection_object) ) ) /* all server connections have to maintain an inactivity watchdog timer */
  841. {
  842. if(elapsed_time >= connection_object->inactivity_watchdog_timer) {
  843. /* we have a timed out connection perform watchdog time out action*/
  844. OPENER_TRACE_INFO(">>>>>>>>>>Connection ConnNr: %u timed out\n",
  845. connection_object->connection_serial_number);
  846. OPENER_ASSERT(NULL != connection_object->connection_timeout_function);
  847. connection_object->connection_timeout_function(connection_object);
  848. } else {
  849. connection_object->inactivity_watchdog_timer -= elapsed_time;
  850. connection_object->last_package_watchdog_timer -= elapsed_time;
  851. }
  852. }
  853. /* only if the connection has not timed out check if data is to be send */
  854. if(kConnectionObjectStateEstablished ==
  855. ConnectionObjectGetState(connection_object) ) {
  856. /* client connection */
  857. if( (0 != ConnectionObjectGetExpectedPacketRate(connection_object) )
  858. && (kEipInvalidSocket !=
  859. connection_object->socket[kUdpCommuncationDirectionProducing]) ) /* only produce for the master connection */
  860. {
  861. if(kConnectionObjectTransportClassTriggerProductionTriggerCyclic !=
  862. ConnectionObjectGetTransportClassTriggerProductionTrigger(
  863. connection_object) ) {
  864. /* non cyclic connections have to decrement production inhibit timer */
  865. if(elapsed_time <= connection_object->production_inhibit_timer) {
  866. //The connection is allowed to send again
  867. } else {
  868. connection_object->production_inhibit_timer -= elapsed_time;
  869. }
  870. }
  871. if(connection_object->transmission_trigger_timer <= elapsed_time) { /* need to send package */
  872. OPENER_ASSERT(
  873. NULL != connection_object->connection_send_data_function);
  874. EipStatus eip_status =
  875. connection_object->connection_send_data_function(connection_object);
  876. if(eip_status == kEipStatusError) {
  877. OPENER_TRACE_ERR(
  878. "sending of UDP data in manage Connection failed\n");
  879. }
  880. /* add the RPI to the timer value */
  881. connection_object->transmission_trigger_timer +=
  882. ConnectionObjectGetRequestedPacketInterval(connection_object);
  883. /* decrecment the elapsed time from timer value, if less than timer value */
  884. if (connection_object->transmission_trigger_timer > elapsed_time) {
  885. connection_object->transmission_trigger_timer -= elapsed_time;
  886. } else { /* elapsed time was longer than RPI */
  887. connection_object->transmission_trigger_timer = 0;
  888. OPENER_TRACE_INFO("elapsed time: %lu ms was longer than RPI: %u ms\n",
  889. elapsed_time,
  890. ConnectionObjectGetRequestedPacketInterval(connection_object));
  891. }
  892. if(kConnectionObjectTransportClassTriggerProductionTriggerCyclic !=
  893. ConnectionObjectGetTransportClassTriggerProductionTrigger(
  894. connection_object) ) {
  895. /* non cyclic connections have to reload the production inhibit timer */
  896. ConnectionObjectResetProductionInhibitTimer(connection_object);
  897. }
  898. } else {
  899. connection_object->transmission_trigger_timer -= elapsed_time;
  900. }
  901. }
  902. }
  903. }
  904. node = node->next;
  905. }
  906. return kEipStatusOk;
  907. }
  908. /** @brief Assembles the Forward Open Response
  909. *
  910. * @param connection_object pointer to connection Object
  911. * @param message_router_response pointer to message router response
  912. * @param general_status the general status of the response
  913. * @param extended_status extended status in the case of an error otherwise 0
  914. * @return status
  915. * kEipStatusOk .. no reply need to be sent back
  916. * kEipStatusOkSend .. need to send reply
  917. * kEipStatusError .. error
  918. */
  919. EipStatus AssembleForwardOpenResponse(CipConnectionObject *connection_object,
  920. CipMessageRouterResponse *message_router_response,
  921. EipUint8 general_status,
  922. EipUint16 extended_status) {
  923. /* write reply information in CPF struct dependent of pa_status */
  924. CipCommonPacketFormatData *cip_common_packet_format_data =
  925. &g_common_packet_format_data_item;
  926. cip_common_packet_format_data->item_count = 2;
  927. cip_common_packet_format_data->data_item.type_id =
  928. kCipItemIdUnconnectedDataItem;
  929. AddNullAddressItem(cip_common_packet_format_data);
  930. CIPServiceCode service_code = kForwardOpen;
  931. if(connection_object->is_large_forward_open) {
  932. service_code = kLargeForwardOpen;
  933. }
  934. message_router_response->reply_service = (0x80 | service_code);
  935. message_router_response->general_status = general_status;
  936. if(kCipErrorSuccess == general_status) {
  937. OPENER_TRACE_INFO("assembleFWDOpenResponse: sending success response\n");
  938. /* if there is no application specific data, total length should be 26 */
  939. message_router_response->size_of_additional_status = 0;
  940. if(cip_common_packet_format_data->address_info_item[0].type_id != 0) {
  941. cip_common_packet_format_data->item_count = 3;
  942. if(cip_common_packet_format_data->address_info_item[1].type_id != 0) {
  943. cip_common_packet_format_data->item_count = 4; /* there are two sockaddrinfo items to add */
  944. }
  945. }
  946. AddDintToMessage(connection_object->cip_consumed_connection_id,
  947. &message_router_response->message);
  948. AddDintToMessage(connection_object->cip_produced_connection_id,
  949. &message_router_response->message);
  950. } else {
  951. /* we have an connection creation error */
  952. OPENER_TRACE_WARN("AssembleForwardOpenResponse: sending error response, general/extended status=%d/%d\n", general_status, extended_status);
  953. ConnectionObjectSetState(connection_object,
  954. kConnectionObjectStateNonExistent);
  955. /* Expected data length is 10 octets */
  956. switch(general_status) {
  957. case kCipErrorNotEnoughData:
  958. case kCipErrorTooMuchData: {
  959. message_router_response->size_of_additional_status = 0;
  960. break;
  961. }
  962. default: {
  963. switch(extended_status) {
  964. case
  965. kConnectionManagerExtendedStatusCodeErrorInvalidOToTConnectionSize:
  966. {
  967. message_router_response->size_of_additional_status = 2;
  968. message_router_response->additional_status[0] = extended_status;
  969. message_router_response->additional_status[1] =
  970. connection_object->correct_originator_to_target_size;
  971. break;
  972. }
  973. case
  974. kConnectionManagerExtendedStatusCodeErrorInvalidTToOConnectionSize:
  975. {
  976. message_router_response->size_of_additional_status = 2;
  977. message_router_response->additional_status[0] = extended_status;
  978. message_router_response->additional_status[1] =
  979. connection_object->correct_target_to_originator_size;
  980. break;
  981. }
  982. default: {
  983. message_router_response->size_of_additional_status = 1;
  984. message_router_response->additional_status[0] = extended_status;
  985. break;
  986. }
  987. }
  988. break;
  989. }
  990. }
  991. }
  992. AddIntToMessage(connection_object->connection_serial_number,
  993. &message_router_response->message);
  994. AddIntToMessage(connection_object->originator_vendor_id,
  995. &message_router_response->message);
  996. AddDintToMessage(connection_object->originator_serial_number,
  997. &message_router_response->message);
  998. if(kCipErrorSuccess == general_status) {
  999. /* set the actual packet rate to requested packet rate */
  1000. AddDintToMessage(connection_object->o_to_t_requested_packet_interval,
  1001. &message_router_response->message);
  1002. AddDintToMessage(connection_object->t_to_o_requested_packet_interval,
  1003. &message_router_response->message);
  1004. }
  1005. AddSintToMessage(0, &message_router_response->message); /* remaining path size - for routing devices relevant */
  1006. AddSintToMessage(0, &message_router_response->message); /* reserved */
  1007. return kEipStatusOkSend; /* send reply */
  1008. }
  1009. /**
  1010. * @brief Adds a Null Address Item to the common data packet format data
  1011. * @param common_data_packet_format_data The CPF data packet where the Null Address Item shall be added
  1012. */
  1013. void AddNullAddressItem(
  1014. CipCommonPacketFormatData *common_data_packet_format_data) {
  1015. /* Precondition: Null Address Item only valid in unconnected messages */
  1016. assert(
  1017. common_data_packet_format_data->data_item.type_id ==
  1018. kCipItemIdUnconnectedDataItem);
  1019. common_data_packet_format_data->address_item.type_id = kCipItemIdNullAddress;
  1020. common_data_packet_format_data->address_item.length = 0;
  1021. }
  1022. /* INT8 assembleFWDCloseResponse(UINT16 pa_ConnectionSerialNr, UINT16 pa_OriginatorVendorID, UINT32 pa_OriginatorSerialNr, S_CIP_MR_Request *pa_MRRequest, S_CIP_MR_Response *pa_MRResponse, S_CIP_CPF_Data *pa_CPF_data, INT8 pa_status, INT8 *pa_msg)
  1023. * create FWDClose response dependent on status.
  1024. * pa_ConnectionSerialNr requested ConnectionSerialNr
  1025. * pa_OriginatorVendorID requested OriginatorVendorID
  1026. * pa_OriginatorSerialNr requested OriginalSerialNr
  1027. * pa_MRRequest pointer to message router request
  1028. * pa_MRResponse pointer to message router response
  1029. * pa_CPF_data pointer to CPF Data Item
  1030. * pa_status status of FWDClose
  1031. * pa_msg pointer to memory where reply has to be stored
  1032. * return status
  1033. * 0 .. no reply need to ne sent back
  1034. * 1 .. need to send reply
  1035. * -1 .. error
  1036. */
  1037. EipStatus AssembleForwardCloseResponse(EipUint16 connection_serial_number,
  1038. EipUint16 originatior_vendor_id,
  1039. EipUint32 originator_serial_number,
  1040. CipMessageRouterRequest *message_router_request,
  1041. CipMessageRouterResponse *message_router_response,
  1042. EipUint16 extended_error_code) {
  1043. /* write reply information in CPF struct dependent of pa_status */
  1044. CipCommonPacketFormatData *common_data_packet_format_data =
  1045. &g_common_packet_format_data_item;
  1046. common_data_packet_format_data->item_count = 2;
  1047. common_data_packet_format_data->data_item.type_id =
  1048. kCipItemIdUnconnectedDataItem;
  1049. AddNullAddressItem(common_data_packet_format_data);
  1050. AddIntToMessage(connection_serial_number, &message_router_response->message);
  1051. AddIntToMessage(originatior_vendor_id, &message_router_response->message);
  1052. AddDintToMessage(originator_serial_number, &message_router_response->message);
  1053. message_router_response->reply_service =
  1054. (0x80 | message_router_request->service);
  1055. /* Excepted length is 10 if there is no application specific data */
  1056. if(kConnectionManagerExtendedStatusCodeSuccess == extended_error_code) {
  1057. AddSintToMessage(0, &message_router_response->message); /* no application data */
  1058. message_router_response->general_status = kCipErrorSuccess;
  1059. message_router_response->size_of_additional_status = 0;
  1060. } else {
  1061. AddSintToMessage(*message_router_request->data,
  1062. &message_router_response->message); /* remaining path size */
  1063. if(kConnectionManagerExtendedStatusWrongCloser == extended_error_code) {
  1064. message_router_response->general_status = kCipErrorPrivilegeViolation;
  1065. } else {
  1066. message_router_response->general_status = kCipErrorConnectionFailure;
  1067. message_router_response->additional_status[0] = extended_error_code;
  1068. message_router_response->size_of_additional_status = 1;
  1069. }
  1070. }
  1071. AddSintToMessage(0, &message_router_response->message); /* reserved */
  1072. return kEipStatusOkSend;
  1073. }
  1074. CipConnectionObject *GetConnectedObject(const EipUint32 connection_id) {
  1075. DoublyLinkedListNode *iterator = connection_list.first;
  1076. while(NULL != iterator) {
  1077. if(kConnectionObjectStateEstablished ==
  1078. ConnectionObjectGetState(iterator->data)
  1079. && connection_id ==
  1080. ConnectionObjectGetCipConsumedConnectionID(iterator->data) ) {
  1081. return iterator->data;
  1082. }
  1083. iterator = iterator->next;
  1084. }
  1085. return NULL;
  1086. }
  1087. CipConnectionObject *GetConnectedOutputAssembly(
  1088. const EipUint32 output_assembly_id) {
  1089. DoublyLinkedListNode *iterator = connection_list.first;
  1090. while(NULL != iterator) {
  1091. if(kConnectionObjectInstanceTypeIOExclusiveOwner ==
  1092. ConnectionObjectGetInstanceType(iterator->data)
  1093. && (kConnectionObjectStateEstablished ==
  1094. ConnectionObjectGetState(iterator->data)
  1095. || kConnectionObjectStateTimedOut ==
  1096. ConnectionObjectGetState(iterator->data) )
  1097. && output_assembly_id ==
  1098. ( (CipConnectionObject *) iterator->data )->produced_path.instance_id) {
  1099. return iterator->data;
  1100. }
  1101. iterator = iterator->next;
  1102. }
  1103. return NULL;
  1104. }
  1105. CipConnectionObject *CheckForExistingConnection(
  1106. const CipConnectionObject *const connection_object) {
  1107. DoublyLinkedListNode *iterator = connection_list.first;
  1108. while(NULL != iterator) {
  1109. if(kConnectionObjectStateEstablished ==
  1110. ConnectionObjectGetState(iterator->data) ) {
  1111. if(EqualConnectionTriad(connection_object, iterator->data) ) {
  1112. return iterator->data;
  1113. }
  1114. }
  1115. iterator = iterator->next;
  1116. }
  1117. return NULL;
  1118. }
  1119. EipStatus CheckElectronicKeyData(EipUint8 key_format,
  1120. void *key_data,
  1121. EipUint16 *extended_status) {
  1122. /* Default return value */
  1123. *extended_status = kConnectionManagerExtendedStatusCodeSuccess;
  1124. /* Check key format */
  1125. if(4 != key_format) {
  1126. *extended_status =
  1127. kConnectionManagerExtendedStatusCodeErrorInvalidSegmentTypeInPath;
  1128. return kEipStatusError;
  1129. }
  1130. bool compatiblity_mode = ElectronicKeyFormat4GetMajorRevisionCompatibility(
  1131. key_data);
  1132. /* Check VendorID and ProductCode, must match, or 0 */
  1133. if( ( (ElectronicKeyFormat4GetVendorId(key_data) != g_identity.vendor_id) &&
  1134. (ElectronicKeyFormat4GetVendorId(key_data) != 0) )
  1135. || ( (ElectronicKeyFormat4GetProductCode(key_data) !=
  1136. g_identity.product_code) &&
  1137. (ElectronicKeyFormat4GetProductCode(key_data) != 0) ) ) {
  1138. *extended_status =
  1139. kConnectionManagerExtendedStatusCodeErrorVendorIdOrProductcodeError;
  1140. return kEipStatusError;
  1141. } else {
  1142. /* VendorID and ProductCode are correct */
  1143. /* Check DeviceType, must match or 0 */
  1144. if( (ElectronicKeyFormat4GetDeviceType(key_data) !=
  1145. g_identity.device_type) &&
  1146. (ElectronicKeyFormat4GetDeviceType(key_data) != 0) ) {
  1147. *extended_status =
  1148. kConnectionManagerExtendedStatusCodeErrorDeviceTypeError;
  1149. return kEipStatusError;
  1150. } else {
  1151. /* VendorID, ProductCode and DeviceType are correct */
  1152. if(false == compatiblity_mode) {
  1153. /* Major = 0 is valid */
  1154. if(0 == ElectronicKeyFormat4GetMajorRevision(key_data) ) {
  1155. return kEipStatusOk;
  1156. }
  1157. /* Check Major / Minor Revision, Major must match, Minor match or 0 */
  1158. if( (ElectronicKeyFormat4GetMajorRevision(key_data) !=
  1159. g_identity.revision.major_revision)
  1160. || ( (ElectronicKeyFormat4GetMinorRevision(key_data) !=
  1161. g_identity.revision.minor_revision) &&
  1162. (ElectronicKeyFormat4GetMinorRevision(key_data) != 0) ) ) {
  1163. *extended_status =
  1164. kConnectionManagerExtendedStatusCodeErrorRevisionMismatch;
  1165. return kEipStatusError;
  1166. }
  1167. } else {
  1168. /* Compatibility mode is set */
  1169. /* Major must match, Minor != 0 and <= MinorRevision */
  1170. if( (ElectronicKeyFormat4GetMajorRevision(key_data) ==
  1171. g_identity.revision.major_revision) &&
  1172. (ElectronicKeyFormat4GetMinorRevision(key_data) > 0)
  1173. && (ElectronicKeyFormat4GetMinorRevision(key_data) <=
  1174. g_identity.revision.minor_revision) ) {
  1175. return kEipStatusOk;
  1176. } else {
  1177. *extended_status =
  1178. kConnectionManagerExtendedStatusCodeErrorRevisionMismatch;
  1179. return kEipStatusError;
  1180. }
  1181. } /* end if CompatiblityMode handling */
  1182. }
  1183. }
  1184. return (*extended_status ==
  1185. kConnectionManagerExtendedStatusCodeSuccess) ? kEipStatusOk :
  1186. kEipStatusError;
  1187. }
  1188. EipUint8 ParseConnectionPath(CipConnectionObject *connection_object,
  1189. CipMessageRouterRequest *message_router_request,
  1190. EipUint16 *extended_error) {
  1191. const EipUint8 *message = message_router_request->data;
  1192. const size_t connection_path_size = GetUsintFromMessage(&message); /* length in words */
  1193. if(0 == connection_path_size) {
  1194. // A (large) forward open request needs to have a connection path size larger than 0
  1195. return kEipStatusError;
  1196. }
  1197. size_t remaining_path = connection_path_size;
  1198. OPENER_TRACE_INFO("Received connection path size: %zu \n",
  1199. connection_path_size);
  1200. CipClass *class = NULL;
  1201. CipDword class_id = 0x0;
  1202. CipInstanceNum instance_id = 0x0;
  1203. /* with 256 we mark that we haven't got a PIT segment */
  1204. ConnectionObjectSetProductionInhibitTime(connection_object, 256);
  1205. size_t header_length = g_kForwardOpenHeaderLength;
  1206. if(connection_object->is_large_forward_open) {
  1207. header_length = g_kLargeForwardOpenHeaderLength;
  1208. }
  1209. if( ( header_length + remaining_path * sizeof(CipWord) ) <
  1210. message_router_request->request_data_size ) {
  1211. /* the received packet is larger than the data in the path */
  1212. *extended_error = 0;
  1213. return kCipErrorTooMuchData;
  1214. }
  1215. if( ( header_length + remaining_path * sizeof(CipWord) ) >
  1216. message_router_request->request_data_size ) {
  1217. /*there is not enough data in received packet */
  1218. *extended_error = 0;
  1219. OPENER_TRACE_INFO("Message not long enough for path\n");
  1220. return kCipErrorNotEnoughData;
  1221. }
  1222. if(remaining_path > 0) {
  1223. /* first look if there is an electronic key */
  1224. if(kSegmentTypeLogicalSegment == GetPathSegmentType(message) ) {
  1225. if(kLogicalSegmentLogicalTypeSpecial ==
  1226. GetPathLogicalSegmentLogicalType(message) ) {
  1227. if(kLogicalSegmentSpecialTypeLogicalFormatElectronicKey ==
  1228. GetPathLogicalSegmentSpecialTypeLogicalType(message) ) {
  1229. if(kElectronicKeySegmentFormatKeyFormat4 ==
  1230. GetPathLogicalSegmentElectronicKeyFormat(message) ) {
  1231. /* Check if there is enough data for holding the electronic key segment */
  1232. if(remaining_path < 5) {
  1233. *extended_error = 0;
  1234. OPENER_TRACE_INFO("Message not long enough for electronic key\n");
  1235. return kCipErrorNotEnoughData;
  1236. }
  1237. /* Electronic key format 4 found */
  1238. connection_object->electronic_key.key_format = 4;
  1239. ElectronicKeyFormat4 *electronic_key = ElectronicKeyFormat4New();
  1240. GetElectronicKeyFormat4FromMessage(&message, electronic_key);
  1241. /* logical electronic key found */
  1242. connection_object->electronic_key.key_data = electronic_key;
  1243. remaining_path -= 5; /*length of the electronic key*/
  1244. OPENER_TRACE_INFO(
  1245. "key: ven ID %d, dev type %d, prod code %d, major %d, minor %d\n",
  1246. ElectronicKeyFormat4GetVendorId(connection_object->electronic_key.
  1247. key_data),
  1248. ElectronicKeyFormat4GetDeviceType(connection_object->
  1249. electronic_key.key_data),
  1250. ElectronicKeyFormat4GetProductCode(connection_object->
  1251. electronic_key.key_data),
  1252. ElectronicKeyFormat4GetMajorRevision(connection_object->
  1253. electronic_key.key_data),
  1254. ElectronicKeyFormat4GetMinorRevision(connection_object->
  1255. electronic_key.key_data) );
  1256. if(kEipStatusOk
  1257. != CheckElectronicKeyData(connection_object->electronic_key.
  1258. key_format,
  1259. connection_object->electronic_key.
  1260. key_data,
  1261. extended_error) ) {
  1262. ElectronicKeyFormat4Delete(&electronic_key);
  1263. return kCipErrorConnectionFailure;
  1264. }
  1265. ElectronicKeyFormat4Delete(&electronic_key);
  1266. }
  1267. } else {
  1268. OPENER_TRACE_INFO("no key\n");
  1269. }
  1270. }
  1271. }
  1272. //TODO: Refactor this afterwards
  1273. if(kConnectionObjectTransportClassTriggerProductionTriggerCyclic !=
  1274. ConnectionObjectGetTransportClassTriggerProductionTrigger(
  1275. connection_object) )
  1276. {
  1277. /*non cyclic connections may have a production inhibit */
  1278. if(kSegmentTypeNetworkSegment == GetPathSegmentType(message) ) {
  1279. NetworkSegmentSubtype network_segment_subtype =
  1280. GetPathNetworkSegmentSubtype(message);
  1281. if(kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds ==
  1282. network_segment_subtype) {
  1283. OPENER_TRACE_INFO("PIT segment available - value: %u\n",message[1]);
  1284. connection_object->production_inhibit_time = message[1];
  1285. message += 2;
  1286. remaining_path -= 1;
  1287. }
  1288. }
  1289. }
  1290. if(kSegmentTypeLogicalSegment == GetPathSegmentType(message) &&
  1291. kLogicalSegmentLogicalTypeClassId ==
  1292. GetPathLogicalSegmentLogicalType(message) ) {
  1293. class_id = CipEpathGetLogicalValue(&message);
  1294. class = GetCipClass(class_id);
  1295. if(NULL == class) {
  1296. OPENER_TRACE_ERR("classid %" PRIx32 " not found\n",
  1297. class_id);
  1298. if(class_id >= 0xC8) { /*reserved range of class ids */
  1299. *extended_error =
  1300. kConnectionManagerExtendedStatusCodeErrorInvalidSegmentTypeInPath;
  1301. } else {
  1302. *extended_error =
  1303. kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
  1304. }
  1305. return kCipErrorConnectionFailure;
  1306. }
  1307. OPENER_TRACE_INFO("classid %" PRIx32 " (%s)\n",
  1308. class_id,
  1309. class->class_name);
  1310. } else {
  1311. *extended_error =
  1312. kConnectionManagerExtendedStatusCodeErrorInvalidSegmentTypeInPath;
  1313. return kCipErrorConnectionFailure;
  1314. }
  1315. remaining_path -= 1; /* 1 16Bit word for the class part of the path */
  1316. /* Get instance ID */
  1317. if(kSegmentTypeLogicalSegment == GetPathSegmentType(message) &&
  1318. kLogicalSegmentLogicalTypeInstanceId ==
  1319. GetPathLogicalSegmentLogicalType(message) ) { /* store the configuration ID for later checking in the application connection types */
  1320. const CipDword temp_id = CipEpathGetLogicalValue(&message);
  1321. OPENER_TRACE_INFO("Configuration instance id %" PRId32 "\n",
  1322. temp_id);
  1323. if( (temp_id > kCipInstanceNumMax) ||
  1324. ( NULL == GetCipInstance(class, (CipInstanceNum)temp_id) ) ) {
  1325. /*according to the test tool we should respond with this extended error code */
  1326. *extended_error =
  1327. kConnectionManagerExtendedStatusCodeErrorInvalidSegmentTypeInPath;
  1328. return kCipErrorConnectionFailure;
  1329. }
  1330. instance_id = (CipInstanceNum)temp_id;
  1331. /* 1 or 2 16Bit words for the configuration instance part of the path */
  1332. remaining_path -= (instance_id > 0xFF) ? 2 : 1; //TODO: 32 bit case missing
  1333. } else {
  1334. OPENER_TRACE_INFO("no config data\n");
  1335. }
  1336. if(kConnectionObjectTransportClassTriggerTransportClass3 ==
  1337. ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
  1338. {
  1339. /*we have Class 3 connection*/
  1340. if(remaining_path > 0) {
  1341. OPENER_TRACE_WARN(
  1342. "Too much data in connection path for class 3 connection\n");
  1343. *extended_error =
  1344. kConnectionManagerExtendedStatusCodeErrorInvalidSegmentTypeInPath;
  1345. return kCipErrorConnectionFailure;
  1346. }
  1347. /* connection end point has to be the message router instance 1 */
  1348. if( (class_id != kCipMessageRouterClassCode) || (1 != instance_id) ) {
  1349. *extended_error =
  1350. kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
  1351. return kCipErrorConnectionFailure;
  1352. }
  1353. /* Configuration connection point is producing connection point */
  1354. CipConnectionPathEpath connection_epath =
  1355. { .class_id = class_id, .instance_id = instance_id,
  1356. .attribute_id_or_connection_point = 0 };
  1357. memcpy(&(connection_object->configuration_path),
  1358. &connection_epath,
  1359. sizeof(connection_object->configuration_path) );
  1360. memcpy(&(connection_object->produced_path), &connection_epath,
  1361. sizeof(connection_object->produced_path) );
  1362. /* End class 3 connection handling */
  1363. } else { /* we have an IO connection */
  1364. CipConnectionPathEpath connection_epath =
  1365. { .class_id = class_id, .instance_id = instance_id,
  1366. .attribute_id_or_connection_point = 0 };
  1367. memcpy(&(connection_object->configuration_path),
  1368. &connection_epath,
  1369. sizeof(connection_object->configuration_path) );
  1370. ConnectionObjectConnectionType originator_to_target_connection_type =
  1371. ConnectionObjectGetOToTConnectionType(connection_object);
  1372. ConnectionObjectConnectionType target_to_originator_connection_type =
  1373. ConnectionObjectGetTToOConnectionType(connection_object);
  1374. connection_object->consumed_connection_path_length = 0;
  1375. connection_object->consumed_connection_path = NULL;
  1376. //connection_object->connection_path.connection_point[1] = 0; /* set not available path to Invalid */
  1377. size_t number_of_encoded_paths = 0;
  1378. CipConnectionPathEpath *paths_to_encode[2] = { 0 };
  1379. if(kConnectionObjectConnectionTypeNull ==
  1380. originator_to_target_connection_type) {
  1381. if(kConnectionObjectConnectionTypeNull ==
  1382. target_to_originator_connection_type) { /* configuration only connection */
  1383. number_of_encoded_paths = 0;
  1384. OPENER_TRACE_WARN("assembly: type invalid\n");
  1385. } else { /* 1 path -> path is for production */
  1386. OPENER_TRACE_INFO("assembly: type produce\n");
  1387. number_of_encoded_paths = 1;
  1388. paths_to_encode[0] = &(connection_object->produced_path);
  1389. }
  1390. } else {
  1391. if(kConnectionObjectConnectionTypeNull ==
  1392. target_to_originator_connection_type) { /* 1 path -> path is for consumption */
  1393. OPENER_TRACE_INFO("assembly: type consume\n");
  1394. number_of_encoded_paths = 1;
  1395. paths_to_encode[0] = &(connection_object->consumed_path);
  1396. } else { /* 2 paths -> 1st for production 2nd for consumption */
  1397. OPENER_TRACE_INFO("assembly: type bidirectional\n");
  1398. paths_to_encode[0] = &(connection_object->consumed_path);
  1399. paths_to_encode[1] = &(connection_object->produced_path);
  1400. number_of_encoded_paths = 2;
  1401. }
  1402. }
  1403. for(size_t i = 0; i < number_of_encoded_paths; i++) /* process up to 2 encoded paths */
  1404. {
  1405. if(kSegmentTypeLogicalSegment == GetPathSegmentType(message)
  1406. && (kLogicalSegmentLogicalTypeInstanceId ==
  1407. GetPathLogicalSegmentLogicalType(message)
  1408. || kLogicalSegmentLogicalTypeConnectionPoint ==
  1409. GetPathLogicalSegmentLogicalType(message) ) ) /* Connection Point interpreted as InstanceNr -> only in Assembly Objects */
  1410. { /* Attribute Id or Connection Point */
  1411. /* Validate encoded instance number. */
  1412. const CipDword temp_instance_id = CipEpathGetLogicalValue(&message);
  1413. if (temp_instance_id > kCipInstanceNumMax) {
  1414. *extended_error =
  1415. kConnectionManagerExtendedStatusCodeErrorInvalidSegmentTypeInPath;
  1416. return kCipErrorConnectionFailure;
  1417. }
  1418. instance_id = (CipInstanceNum)temp_instance_id;
  1419. CipConnectionPathEpath path;
  1420. path.class_id = class_id;
  1421. path.instance_id = instance_id;
  1422. path.attribute_id_or_connection_point = 0;
  1423. memcpy(paths_to_encode[i], &path,
  1424. sizeof(connection_object->produced_path) );
  1425. OPENER_TRACE_INFO(
  1426. "connection point %" PRIu32 "\n",
  1427. instance_id);
  1428. if( NULL == GetCipInstance(class, instance_id) ) {
  1429. *extended_error =
  1430. kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
  1431. return kCipErrorConnectionFailure;
  1432. }
  1433. /* 1 or 2 16Bit word for the connection point part of the path */
  1434. remaining_path -= (instance_id > 0xFF) ? 2 : 1;
  1435. } else {
  1436. *extended_error =
  1437. kConnectionManagerExtendedStatusCodeErrorInvalidSegmentTypeInPath;
  1438. return kCipErrorConnectionFailure;
  1439. }
  1440. }
  1441. g_config_data_length = 0;
  1442. g_config_data_buffer = NULL;
  1443. while(remaining_path > 0) { /* remaining_path_size something left in the path should be configuration data */
  1444. SegmentType segment_type = GetPathSegmentType(message);
  1445. switch(segment_type) {
  1446. case kSegmentTypeDataSegment: {
  1447. DataSegmentSubtype data_segment_type = GetPathDataSegmentSubtype(
  1448. message);
  1449. switch(data_segment_type) {
  1450. case kDataSegmentSubtypeSimpleData:
  1451. g_config_data_length = message[1] * 2; /*data segments store length 16-bit word wise */
  1452. g_config_data_buffer = (EipUint8 *) message + 2;
  1453. remaining_path -= (g_config_data_length + 2) / 2;
  1454. message += (g_config_data_length + 2);
  1455. break;
  1456. default:
  1457. OPENER_TRACE_ERR("Not allowed in connection manager");
  1458. return kCipErrorPathSegmentError;
  1459. }
  1460. }
  1461. break;
  1462. case kSegmentTypeNetworkSegment: {
  1463. NetworkSegmentSubtype subtype =
  1464. GetPathNetworkSegmentSubtype(message);
  1465. switch(subtype) {
  1466. case kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds:
  1467. if(kConnectionObjectTransportClassTriggerProductionTriggerCyclic
  1468. != ConnectionObjectGetTransportClassTriggerProductionTrigger(
  1469. connection_object) ) {
  1470. /* only non cyclic connections may have a production inhibit */
  1471. connection_object->production_inhibit_time = message[1];
  1472. message += 2;
  1473. remaining_path -= 2;
  1474. } else {
  1475. *extended_error = connection_path_size - remaining_path; /*offset in 16Bit words where within the connection path the error happened*/
  1476. return kCipErrorPathSegmentError; /*status code for invalid segment type*/
  1477. }
  1478. break;
  1479. default:
  1480. OPENER_TRACE_ERR("Not allowed in connection manager");
  1481. return kCipErrorPathSegmentError;
  1482. }
  1483. }
  1484. break;
  1485. default:
  1486. OPENER_TRACE_WARN(
  1487. "No data segment identifier found for the configuration data\n");
  1488. *extended_error = connection_path_size - remaining_path; /*offset in 16Bit words where within the connection path the error happened*/
  1489. return
  1490. kConnectionManagerGeneralStatusPathSegmentErrorInUnconnectedSend;
  1491. }
  1492. }
  1493. }
  1494. }
  1495. OPENER_TRACE_INFO("Resulting PIT value: %u\n",
  1496. connection_object->production_inhibit_time);
  1497. /*save back the current position in the stream allowing followers to parse anything thats still there*/
  1498. message_router_request->data = message;
  1499. return kEipStatusOk;
  1500. }
  1501. void CloseConnection(CipConnectionObject *RESTRICT connection_object) {
  1502. OPENER_TRACE_INFO("cipconnectionmanager: CloseConnection, trigger: %d \n",
  1503. ConnectionObjectGetTransportClassTriggerTransportClass(connection_object));
  1504. if(kConnectionObjectTransportClassTriggerTransportClass3 !=
  1505. ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
  1506. {
  1507. /* only close the UDP connection for not class 3 connections */
  1508. CloseUdpSocket(connection_object->socket[kUdpCommuncationDirectionConsuming]);
  1509. connection_object->socket[kUdpCommuncationDirectionConsuming] =
  1510. kEipInvalidSocket;
  1511. CloseUdpSocket(connection_object->socket[kUdpCommuncationDirectionProducing]);
  1512. connection_object->socket[kUdpCommuncationDirectionProducing] =
  1513. kEipInvalidSocket;
  1514. }
  1515. RemoveFromActiveConnections(connection_object);
  1516. ConnectionObjectInitializeEmpty(connection_object);
  1517. }
  1518. void AddNewActiveConnection(CipConnectionObject *const connection_object) {
  1519. DoublyLinkedListInsertAtHead(&connection_list, connection_object);
  1520. ConnectionObjectSetState(connection_object,
  1521. kConnectionObjectStateEstablished);
  1522. }
  1523. void RemoveFromActiveConnections(CipConnectionObject *const connection_object) {
  1524. for(DoublyLinkedListNode *iterator = connection_list.first; iterator != NULL;
  1525. iterator = iterator->next) {
  1526. if(iterator->data == connection_object) {
  1527. DoublyLinkedListRemoveNode(&connection_list, &iterator);
  1528. return;
  1529. }
  1530. } OPENER_TRACE_ERR("Connection not found in active connection list\n");
  1531. }
  1532. EipBool8 IsConnectedOutputAssembly(const CipInstanceNum instance_number) {
  1533. EipBool8 is_connected = false;
  1534. DoublyLinkedListNode *node = connection_list.first;
  1535. while(NULL != node) {
  1536. CipConnectionObject *connection_object = (CipConnectionObject *) node->data;
  1537. CipDword consumed_connection_point =
  1538. connection_object->consumed_path.instance_id;
  1539. if(instance_number == consumed_connection_point &&
  1540. true == ConnectionObjectIsTypeIOConnection(connection_object) ) {
  1541. is_connected = true;
  1542. break;
  1543. }
  1544. node = node->next;
  1545. }
  1546. return is_connected;
  1547. }
  1548. EipStatus AddConnectableObject(const CipUdint class_code,
  1549. OpenConnectionFunction open_connection_function)
  1550. {
  1551. EipStatus status = kEipStatusError;
  1552. /*parsing is now finished all data is available and check now establish the connection */
  1553. for(unsigned int i = 0; i < g_kNumberOfConnectableObjects; ++i) {
  1554. if( (0 == g_connection_management_list[i].class_id) ||
  1555. (class_code == g_connection_management_list[i].class_id) ) {
  1556. g_connection_management_list[i].class_id = class_code;
  1557. g_connection_management_list[i].open_connection_function =
  1558. open_connection_function;
  1559. status = kEipStatusOk;
  1560. break;
  1561. }
  1562. }
  1563. return status;
  1564. }
  1565. ConnectionManagementHandling *
  1566. GetConnectionManagementEntry(const EipUint32 class_id) {
  1567. ConnectionManagementHandling *connection_management_entry = NULL;
  1568. for(unsigned int i = 0; i < g_kNumberOfConnectableObjects; ++i) {
  1569. if(class_id == g_connection_management_list[i].class_id) {
  1570. connection_management_entry = &(g_connection_management_list[i]);
  1571. break;
  1572. }
  1573. }
  1574. return connection_management_entry;
  1575. }
  1576. EipStatus TriggerConnections(unsigned int output_assembly,
  1577. unsigned int input_assembly) {
  1578. EipStatus status = kEipStatusError;
  1579. DoublyLinkedListNode *node = connection_list.first;
  1580. while(NULL != node) {
  1581. CipConnectionObject *connection_object = node->data;
  1582. if( (output_assembly == connection_object->consumed_path.instance_id) &&
  1583. (input_assembly == connection_object->produced_path.instance_id) ) {
  1584. if(
  1585. kConnectionObjectTransportClassTriggerProductionTriggerApplicationObject
  1586. == ConnectionObjectGetTransportClassTriggerProductionTrigger(
  1587. connection_object) ) {
  1588. /* produce at the next allowed occurrence */
  1589. connection_object->transmission_trigger_timer =
  1590. connection_object->production_inhibit_time;
  1591. status = kEipStatusOk;
  1592. }
  1593. break;
  1594. }
  1595. node = node->next;
  1596. }
  1597. return status;
  1598. }
  1599. void CheckForTimedOutConnectionsAndCloseTCPConnections(
  1600. const CipConnectionObject *const connection_object,
  1601. CloseSessionFunction CloseSessions)
  1602. {
  1603. DoublyLinkedListNode *search_node = connection_list.first;
  1604. bool non_timed_out_connection_found = false;
  1605. while(NULL != search_node) {
  1606. CipConnectionObject *search_connection = search_node->data;
  1607. if(ConnectionObjectEqualOriginator(connection_object,
  1608. search_connection) &&
  1609. connection_object != search_connection
  1610. && kConnectionObjectStateTimedOut !=
  1611. ConnectionObjectGetState(search_connection) ) {
  1612. non_timed_out_connection_found = true;
  1613. break;
  1614. }
  1615. search_node = search_node->next;
  1616. }
  1617. if(false == non_timed_out_connection_found) {
  1618. CloseSessions(connection_object);
  1619. }
  1620. }
  1621. void InitializeConnectionManagerData() {
  1622. memset(g_connection_management_list,
  1623. 0,
  1624. g_kNumberOfConnectableObjects * sizeof(ConnectionManagementHandling) );
  1625. InitializeClass3ConnectionData();
  1626. InitializeIoConnectionData();
  1627. }