ciptcpipinterface.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*******************************************************************************
  2. * Copyright (c) 2009, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. #include "ciptcpipinterface.h"
  7. #include <string.h>
  8. #include "opener_user_conf.h"
  9. #include "cipcommon.h"
  10. #include "cipmessagerouter.h"
  11. #include "ciperror.h"
  12. #include "endianconv.h"
  13. #include "cipethernetlink.h"
  14. #include "opener_api.h"
  15. #include "trace.h"
  16. #include "cipassembly.h"
  17. /** definition of TCP/IP object instance 1 data */
  18. CipTcpIpObject g_tcpip =
  19. {
  20. .status = 0x01, /* attribute #1 TCP status with 1 we indicate that we got a valid configuration from DHCP or BOOTP */
  21. .config_capability = 0x04, /* attribute #2 config_capability: This is a default value meaning that it is a DHCP client see 5-3.2.2.2 EIP specification. */
  22. .config_control = 0x02, /* attribute #3 config_control: 0x02 means that the device shall obtain its interface configuration values via DHCP. */
  23. .physical_link_object = { /* attribute #4 physical link object */
  24. 2, /* PathSize in 16 Bit chunks */
  25. CIP_ETHERNETLINK_CLASS_CODE, /* Class Code */
  26. 1, /* Instance # */
  27. 0 /* Attribute # (not used as this is the EPATH to the EthernetLink object)*/
  28. },
  29. .interface_configuration = { /* attribute #5 interface_configuration */
  30. 0, /* IP address */
  31. 0, /* NetworkMask */
  32. 0, /* Gateway */
  33. 0, /* NameServer */
  34. 0, /* NameServer2 */
  35. { /* DomainName */
  36. 0, NULL,
  37. }
  38. },
  39. .hostname = { /* attribute #6 hostname */
  40. 0,
  41. NULL
  42. },
  43. .mcast_ttl_value = 1, /* attribute #8 mcast TTL value */
  44. .mcast_config = { /* attribute #9 multicast configuration */
  45. 0, /* use the default allocation algorithm */
  46. 0, /* reserved */
  47. 1, /* we currently use only one multicast address */
  48. 0 /* the multicast address will be allocated on IP address configuration */
  49. },
  50. .encapsulation_inactivity_timeout = 120 /* attribute #13 encapsulation_inactivity_timeout, use a default value of 120 */
  51. };
  52. /************** Functions ****************************************/
  53. EipStatus GetAttributeSingleTcpIpInterface(
  54. CipInstance *const RESTRICT instance,
  55. CipMessageRouterRequest *const RESTRICT message_router_request,
  56. CipMessageRouterResponse *const RESTRICT message_router_response,
  57. const struct sockaddr *originator_address,
  58. const int encapsulation_session);
  59. EipStatus GetAttributeAllTcpIpInterface(
  60. CipInstance *instance,
  61. CipMessageRouterRequest *message_router_request,
  62. CipMessageRouterResponse *message_router_response,
  63. const struct sockaddr *originator_address,
  64. const int encapsulation_session);
  65. EipStatus SetAttributeSingleTcp(
  66. CipInstance *instance,
  67. CipMessageRouterRequest *message_router_request,
  68. CipMessageRouterResponse *message_router_response,
  69. const struct sockaddr *originator_address,
  70. const int encapsulation_session) {
  71. CipAttributeStruct *attribute = GetCipAttribute(
  72. instance, message_router_request->request_path.attribute_number);
  73. (void) instance; /*Suppress compiler warning */
  74. EipUint16 attribute_number = message_router_request->request_path
  75. .attribute_number;
  76. if (NULL != attribute) {
  77. uint8_t set_bit_mask = (instance->cip_class->set_bit_mask[CalculateIndex(
  78. attribute_number)
  79. ]);
  80. if ( set_bit_mask & ( 1 << ( (attribute_number) % 8 ) ) ) {
  81. switch (attribute_number) {
  82. case 3: {
  83. CipUint configuration_control_recieved = GetDintFromMessage(
  84. &(message_router_request->data) );
  85. if ( (configuration_control_recieved >= 0x03)
  86. && (configuration_control_recieved <= 0x0F) ) {
  87. message_router_response->general_status =
  88. kCipErrorInvalidAttributeValue;
  89. } else {
  90. OPENER_TRACE_INFO(" setAttribute %d\n", attribute_number);
  91. if (attribute->data != NULL) {
  92. CipDword *data = (CipDword *) attribute->data;
  93. *(data) = configuration_control_recieved;
  94. message_router_response->general_status = kCipErrorSuccess;
  95. } else {
  96. message_router_response->general_status = kCipErrorNotEnoughData;
  97. }
  98. }
  99. }
  100. break;
  101. case 13: {
  102. CipUint inactivity_timeout_received = GetIntFromMessage(
  103. &(message_router_request->data) );
  104. if (inactivity_timeout_received > 3600) {
  105. message_router_response->general_status =
  106. kCipErrorInvalidAttributeValue;
  107. } else {
  108. OPENER_TRACE_INFO("setAttribute %d\n", attribute_number);
  109. if (attribute->data != NULL) {
  110. CipUint *data = (CipUint *) attribute->data;
  111. *(data) = inactivity_timeout_received;
  112. message_router_response->general_status = kCipErrorSuccess;
  113. } else {
  114. message_router_response->general_status = kCipErrorNotEnoughData;
  115. }
  116. }
  117. }
  118. break;
  119. default:
  120. message_router_response->general_status =
  121. kCipErrorAttributeNotSetable;
  122. break;
  123. }
  124. } else {
  125. message_router_response->general_status = kCipErrorAttributeNotSetable;
  126. }
  127. } else {
  128. /* we don't have this attribute */
  129. message_router_response->general_status = kCipErrorAttributeNotSupported;
  130. }
  131. message_router_response->size_of_additional_status = 0;
  132. message_router_response->data_length = 0;
  133. message_router_response->reply_service = (0x80
  134. | message_router_request->service);
  135. return kEipStatusOkSend;
  136. }
  137. EipStatus CipTcpIpInterfaceInit() {
  138. CipClass *tcp_ip_class = NULL;
  139. if ( ( tcp_ip_class = CreateCipClass(kCipTcpIpInterfaceClassCode, /* class code */
  140. 0, /* # class attributes */
  141. 7, /* # highest class attribute number */
  142. 2, /* # class services */
  143. 9, /* # instance attributes */
  144. 13, /* # highest instance attribute number */
  145. 3, /* # instance services */
  146. 1, /* # instances */
  147. "TCP/IP interface", 4, /* # class revision */
  148. NULL /* # function pointer for initialization */
  149. ) ) == 0 ) {
  150. return kEipStatusError;
  151. }
  152. CipInstance *instance = GetCipInstance(tcp_ip_class, 1); /* bind attributes to the instance #1 that was created above */
  153. InsertAttribute(instance, 1, kCipDword, (void *) &g_tcpip.status,
  154. kGetableSingleAndAll);
  155. InsertAttribute(instance, 2, kCipDword, (void *) &g_tcpip.config_capability,
  156. kGetableSingleAndAll);
  157. InsertAttribute(instance, 3, kCipDword, (void *) &g_tcpip.config_control,
  158. kSetAndGetAble);
  159. InsertAttribute(instance, 4, kCipEpath, &g_tcpip.physical_link_object,
  160. kGetableSingleAndAll);
  161. InsertAttribute(instance, 5, kCipUdintUdintUdintUdintUdintString,
  162. &g_tcpip.interface_configuration, kGetableSingleAndAll);
  163. InsertAttribute(instance, 6, kCipString, (void *) &g_tcpip.hostname,
  164. kGetableSingleAndAll);
  165. InsertAttribute(instance, 8, kCipUsint, (void *) &g_tcpip.mcast_ttl_value,
  166. kGetableSingleAndAll);
  167. InsertAttribute(instance, 9, kCipAny, (void *) &g_tcpip.mcast_config,
  168. kGetableSingleAndAll);
  169. InsertAttribute(instance,
  170. 13,
  171. kCipUint,
  172. (void *) &g_tcpip.encapsulation_inactivity_timeout,
  173. kSetAndGetAble);
  174. InsertService(tcp_ip_class, kGetAttributeSingle,
  175. &GetAttributeSingleTcpIpInterface,
  176. "GetAttributeSingleTCPIPInterface");
  177. InsertService(tcp_ip_class, kGetAttributeAll, &GetAttributeAllTcpIpInterface,
  178. "GetAttributeAllTCPIPInterface");
  179. InsertService(tcp_ip_class, kSetAttributeSingle, &SetAttributeSingleTcp,
  180. "SetAttributeSingle");
  181. return kEipStatusOk;
  182. }
  183. void ShutdownTcpIpInterface(void) {
  184. /*Only free the resources if they are initialized */
  185. if (NULL != g_tcpip.hostname.string) {
  186. CipFree(g_tcpip.hostname.string);
  187. g_tcpip.hostname.string = NULL;
  188. }
  189. if (NULL != g_tcpip.interface_configuration.domain_name.string) {
  190. CipFree(g_tcpip.interface_configuration.domain_name.string);
  191. g_tcpip.interface_configuration.domain_name.string = NULL;
  192. }
  193. }
  194. EipStatus GetAttributeSingleTcpIpInterface(
  195. CipInstance *const RESTRICT instance,
  196. CipMessageRouterRequest *const RESTRICT message_router_request,
  197. CipMessageRouterResponse *const RESTRICT message_router_response,
  198. const struct sockaddr *originator_address,
  199. const int encapsulation_session) {
  200. EipUint16 attribute_number = message_router_request->request_path
  201. .attribute_number;
  202. /* Use common handler for all attributes except attribute 9. */
  203. if (9 != attribute_number) {
  204. return GetAttributeSingle(instance,
  205. message_router_request,
  206. message_router_response,
  207. originator_address,
  208. encapsulation_session);
  209. }
  210. { /* attribute 9 can not be easily handled with the default mechanism therefore we will do it by hand */
  211. EipByte *message = message_router_response->data;
  212. message_router_response->data_length = 0;
  213. message_router_response->reply_service = (0x80
  214. | message_router_request->service);
  215. message_router_response->size_of_additional_status = 0;
  216. message_router_response->general_status = kCipErrorAttributeNotSupported;
  217. uint8_t get_bit_mask = 0;
  218. if (kGetAttributeAll == message_router_request->service) {
  219. get_bit_mask = (instance->cip_class->get_all_bit_mask[CalculateIndex(
  220. attribute_number)]);
  221. message_router_response->general_status = kCipErrorSuccess;
  222. } else {
  223. get_bit_mask = (instance->cip_class->get_single_bit_mask[CalculateIndex(
  224. attribute_number)
  225. ]);
  226. }
  227. if ( 0 != ( get_bit_mask & ( 1 << (attribute_number % 8) ) ) ) {
  228. OPENER_TRACE_INFO("getAttribute %d\n",
  229. message_router_request->request_path.attribute_number);
  230. /* create a reply message containing the data*/
  231. message_router_response->data_length += EncodeData(
  232. kCipUsint, &(g_tcpip.mcast_config.alloc_control), &message);
  233. message_router_response->data_length += EncodeData(
  234. kCipUsint, &(g_tcpip.mcast_config.reserved_shall_be_zero),
  235. &message);
  236. message_router_response->data_length += EncodeData(
  237. kCipUint,
  238. &(g_tcpip.mcast_config.number_of_allocated_multicast_addresses),
  239. &message);
  240. EipUint32 multicast_address = ntohl(
  241. g_tcpip.mcast_config.starting_multicast_address);
  242. message_router_response->data_length += EncodeData(kCipUdint,
  243. &multicast_address,
  244. &message);
  245. message_router_response->general_status = kCipErrorSuccess;
  246. }
  247. }
  248. return kEipStatusOkSend;
  249. }
  250. EipStatus GetAttributeAllTcpIpInterface(
  251. CipInstance *instance,
  252. CipMessageRouterRequest *message_router_request,
  253. CipMessageRouterResponse *message_router_response,
  254. const struct sockaddr *originator_address,
  255. const int encapsulation_session) {
  256. EipUint8 *response = message_router_response->data; /* pointer into the reply */
  257. CipAttributeStruct *attribute = instance->attributes;
  258. for (int j = 0; j < instance->cip_class->number_of_attributes; j++) /* for each instance attribute of this class */
  259. {
  260. int attribute_number = attribute->attribute_number;
  261. if (attribute_number < 32) /* only return attributes that are flagged as being part of GetAttributeALl */
  262. {
  263. message_router_request->request_path.attribute_number = attribute_number;
  264. if (8 == attribute_number) { /* insert 6 zeros for the required empty safety network number according to Table 5-3.10 */
  265. memset(message_router_response->data, 0, 6);
  266. message_router_response->data += 6;
  267. }
  268. if ( kEipStatusOkSend
  269. != GetAttributeSingleTcpIpInterface(instance, message_router_request,
  270. message_router_response,
  271. originator_address,
  272. encapsulation_session) ) {
  273. message_router_response->data = response;
  274. return kEipStatusError;
  275. }
  276. message_router_response->data += message_router_response->data_length;
  277. if (9 == attribute_number) {
  278. /* returning default value for unimplemented attributes 10,11 and 12 */
  279. /* attribute 10, type: BOOL, default value: 0 */
  280. message_router_response->data += 6;
  281. *(message_router_response->data) = 0;
  282. message_router_response->data += 1;
  283. /* attribute 11, type: STRUCT OF USINT, ARRAY of 6 USINTs, ARRAY of 28 USINTs default value: 0 */
  284. memset(message_router_response->data, 0, 29);
  285. message_router_response->data += 29;
  286. /* attribute 12, type: BOOL default value: 0 */
  287. *(message_router_response->data) = 0;
  288. message_router_response->data += 1;
  289. }
  290. }
  291. attribute++;
  292. }
  293. message_router_response->data_length = message_router_response->data
  294. - response;
  295. message_router_response->data = response;
  296. return kEipStatusOkSend;
  297. }
  298. EipUint16 GetEncapsulationInactivityTimeout(CipInstance *instance) {
  299. CipAttributeStruct *attribute = GetCipAttribute(instance, 13);
  300. OPENER_ASSERT(NULL != attribute)
  301. CipUint * data = (CipUint *) attribute->data;
  302. EipUint16 encapsulation_inactivity_timeout = *data;
  303. return encapsulation_inactivity_timeout;
  304. }