ethlinkcbs.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /******************************************************************************
  2. * Copyright (c) 2019, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. *****************************************************************************/
  6. /** @file
  7. * @brief Ethernet Link object callbacks
  8. *
  9. * This module implements the Ethernet Link object callbacks. These callbacks
  10. * handle the update and clear operation for the interface and media counters
  11. * of every Ethernet Link object of our device.
  12. *
  13. * The current implementation is only a dummy implementation that doesn't
  14. * return real counters of the interface(s). It is only intended to check
  15. * whether the EIP stack transmits the counters at the right position in
  16. * the response while we're are filling the counters in the Ethernet Link
  17. * counter attributes by their union member names.
  18. */
  19. /*---------------------------------------------------------------------------*/
  20. /* INCLUDES */
  21. /*---------------------------------------------------------------------------*/
  22. #include "ethlinkcbs.h"
  23. #include "cipethernetlink.h"
  24. #include "trace.h"
  25. /*---------------------------------------------------------------------------*/
  26. /* LOCALS */
  27. /*---------------------------------------------------------------------------*/
  28. /* These are "dummy" counters that are only used by the check code to be able
  29. * to transmit interface and media counters that change with each
  30. * GetAttribute explicit request.
  31. */
  32. static CipUdint iface_calls[OPENER_ETHLINK_INSTANCE_CNT];
  33. static CipUdint media_calls[OPENER_ETHLINK_INSTANCE_CNT];
  34. /*---------------------------------------------------------------------------*/
  35. /* IMPLEMENTATION */
  36. /*---------------------------------------------------------------------------*/
  37. #if defined(OPENER_ETHLINK_CNTRS_ENABLE) && 0 != OPENER_ETHLINK_CNTRS_ENABLE
  38. /*---------------------------------------------------------------------------*/
  39. /* Here we implement the functions delivering some dummy data created from */
  40. /* the instance number, the attribute number, the position of the data */
  41. /* field in the counters union and the count of GetAttributeSingle calls */
  42. /* for that attribute since startup or last GetAndClear service. */
  43. /* The returned data is calculated using MAKE_CNTR() in a way that the input */
  44. /* values can be easily decoded from the decimal view in the Wireshark log. */
  45. /* This is meant as debugging aid and to check if the individual counter */
  46. /* value is sent at the right position in the Get* service response. */
  47. #define MAKE_CNTR(inst, attr, idx, cnt) ((10000000U * inst) + (100000U * attr) + (1000U * idx) + cnt)
  48. EipStatus EthLnkPreGetCallback
  49. (
  50. CipInstance *const instance,
  51. CipAttributeStruct *const attribute,
  52. CipByte service
  53. )
  54. {
  55. bool hadAction = true;
  56. EipStatus status = kEipStatusOk;
  57. CipUint attr_no = attribute->attribute_number;
  58. /* ATTENTION: Array indices run from 0..(N-1), instance numbers from 1..N */
  59. CipUdint inst_no = instance->instance_number;
  60. unsigned idx = inst_no-1;
  61. switch (attr_no) {
  62. case 4: {
  63. CipEthernetLinkInterfaceCounters *p_iface_cntrs = &g_ethernet_link[idx].interface_cntrs;
  64. ++iface_calls[idx]; /* Count successful calls */
  65. p_iface_cntrs->ul.in_octets = MAKE_CNTR(inst_no, attr_no, 0, iface_calls[idx]);
  66. p_iface_cntrs->ul.in_ucast = MAKE_CNTR(inst_no, attr_no, 1, iface_calls[idx]);
  67. p_iface_cntrs->ul.in_nucast = MAKE_CNTR(inst_no, attr_no, 2, iface_calls[idx]);
  68. p_iface_cntrs->ul.in_discards = MAKE_CNTR(inst_no, attr_no, 3, iface_calls[idx]);
  69. p_iface_cntrs->ul.in_errors = MAKE_CNTR(inst_no, attr_no, 4, iface_calls[idx]);
  70. p_iface_cntrs->ul.in_unknown_protos = MAKE_CNTR(inst_no, attr_no, 5, iface_calls[idx]);
  71. p_iface_cntrs->ul.out_octets = MAKE_CNTR(inst_no, attr_no, 6, iface_calls[idx]);
  72. p_iface_cntrs->ul.out_ucast = MAKE_CNTR(inst_no, attr_no, 7, iface_calls[idx]);
  73. p_iface_cntrs->ul.out_nucast = MAKE_CNTR(inst_no, attr_no, 8, iface_calls[idx]);
  74. p_iface_cntrs->ul.out_discards = MAKE_CNTR(inst_no, attr_no, 9, iface_calls[idx]);
  75. p_iface_cntrs->ul.out_errors = MAKE_CNTR(inst_no, attr_no, 10, iface_calls[idx]);
  76. break;
  77. }
  78. case 5: {
  79. CipEthernetLinkMediaCounters *p_media_cntrs = &g_ethernet_link[idx].media_cntrs;
  80. ++media_calls[idx]; /* Count successful calls */
  81. /* The 1 != mediaCalls[idx] is a concession to the conformance test tool that
  82. * expects the media counters to be zero after a GetAndClear service.
  83. * This way we always transmit zeros after reset or a GetAndClear service. */
  84. if (1 != media_calls[idx]) {
  85. p_media_cntrs->ul.align_errs = MAKE_CNTR(inst_no, attr_no, 0, media_calls[idx]);
  86. p_media_cntrs->ul.fcs_errs = MAKE_CNTR(inst_no, attr_no, 1, media_calls[idx]);
  87. p_media_cntrs->ul.single_coll = MAKE_CNTR(inst_no, attr_no, 2, media_calls[idx]);
  88. p_media_cntrs->ul.multi_coll = MAKE_CNTR(inst_no, attr_no, 3, media_calls[idx]);
  89. p_media_cntrs->ul.sqe_test_errs = MAKE_CNTR(inst_no, attr_no, 4, media_calls[idx]);
  90. p_media_cntrs->ul.def_trans = MAKE_CNTR(inst_no, attr_no, 5, media_calls[idx]);
  91. p_media_cntrs->ul.late_coll = MAKE_CNTR(inst_no, attr_no, 6, media_calls[idx]);
  92. p_media_cntrs->ul.exc_coll = MAKE_CNTR(inst_no, attr_no, 7, media_calls[idx]);
  93. p_media_cntrs->ul.mac_tx_errs = MAKE_CNTR(inst_no, attr_no, 8, media_calls[idx]);
  94. p_media_cntrs->ul.crs_errs = MAKE_CNTR(inst_no, attr_no, 9, media_calls[idx]);
  95. p_media_cntrs->ul.frame_too_long= MAKE_CNTR(inst_no, attr_no, 10, media_calls[idx]);
  96. p_media_cntrs->ul.mac_rx_errs = MAKE_CNTR(inst_no, attr_no, 11, media_calls[idx]);
  97. }
  98. break;
  99. }
  100. default:
  101. hadAction = false;
  102. break;
  103. }
  104. if (hadAction) {
  105. OPENER_TRACE_INFO(
  106. "Eth Link PreCallback: %s, i %" PRIu32 ", a %" PRIu16 ", s %" PRIu8 "\n",
  107. instance->cip_class->class_name,
  108. instance->instance_number,
  109. attribute->attribute_number,
  110. service);
  111. }
  112. return status;
  113. }
  114. EipStatus EthLnkPostGetCallback
  115. (
  116. CipInstance *const instance,
  117. CipAttributeStruct *const attribute,
  118. CipByte service
  119. )
  120. {
  121. CipUdint inst_no = instance->instance_number;
  122. EipStatus status = kEipStatusOk;
  123. if (kEthLinkGetAndClear == (service & 0x7f)) {
  124. OPENER_TRACE_INFO(
  125. "Eth Link PostCallback: %s, i %" PRIu32 ", a %" PRIu16 ", s %" PRIu8 "\n",
  126. instance->cip_class->class_name,
  127. inst_no,
  128. attribute->attribute_number,
  129. service);
  130. /* Clear the instance specific object counters. In this dummy function we only
  131. * clear our GetAttributeSingle PreCallback execution counters. */
  132. switch (attribute->attribute_number) {
  133. case 4:
  134. iface_calls[inst_no-1] = 0U;
  135. break;
  136. case 5:
  137. media_calls[inst_no-1] = 0U;
  138. /* This is a concession to the conformance test tool that expects
  139. * the media counters to be zero after a GetAndClear service. */
  140. for (int idx = 0; idx < 12; ++idx) {
  141. g_ethernet_link[inst_no-1].media_cntrs.cntr32[idx] = 0U;
  142. }
  143. break;
  144. default:
  145. OPENER_TRACE_INFO(
  146. "Wrong attribute number %" PRIu16 " in GetAndClear callback\n",
  147. attribute->attribute_number);
  148. break;
  149. }
  150. }
  151. return status;
  152. }
  153. #endif /* ... && 0 != OPENER_ETHLINK_CNTRS_ENABLE */