| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716 |
- /*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
- #include "ciptcpipinterface.h"
- #include <string.h>
- #include "opener_user_conf.h"
- #include "cipcommon.h"
- #include "cipconnectionobject.h"
- #include "cipmessagerouter.h"
- #include "ciperror.h"
- #include "cipstring.h"
- #include "endianconv.h"
- #include "cipethernetlink.h"
- #include "opener_api.h"
- #include "trace.h"
- #include "cipassembly.h"
- /* Define constants to initialize the config_capability attribute (#2). These
- * are needed as defines because we use them for static initialization. */
- #define CFG_CAPS_BOOTP_CLIENT 0x01U /**< Device has BOOTP client */
- #define CFG_CAPS_DNS_CLIENT 0x02U /**< Device has DNS client */
- #define CFG_CAPS_DHCP_CLIENT 0x04U /**< Device has DHCP client */
- #define CFG_CAPS_CFG_SETTABLE 0x10U /**< Interface configuration can be set */
- #define CFG_CAPS_CFG_CHG_NEEDS_RESET 0x40U /**< Interface configuration change needs RESET */
- #define CFG_CAPS_ACD_CAPABLE 0x80U /**< Device supports ACD */
- /* OPENER_TCPIP_IFACE_CFG_SETTABLE controls if the interface configuration is fully settable.
- * Prepare additional defines needed here:
- * - IFACE_CFG_SET_MODE is used to initialize the set mode of the affected attributes (3, 5, 6).
- * - CFG_CAPS is the matching initial value for .config_capability
- */
- #if defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && \
- 0 != OPENER_TCPIP_IFACE_CFG_SETTABLE
- #define IFACE_CFG_SET_MODE kSetable
- #define CFG_CAPS (CFG_CAPS_DHCP_CLIENT | CFG_CAPS_CFG_SETTABLE | \
- CFG_CAPS_CFG_CHG_NEEDS_RESET)
- #else
- #define IFACE_CFG_SET_MODE kNotSetOrGetable
- #define CFG_CAPS (CFG_CAPS_DHCP_CLIENT)
- #endif
- /** definition of TCP/IP object instance 1 data */
- CipTcpIpObject g_tcpip =
- {
- .status = 0x01, /* attribute #1 TCP status with 1 we indicate that we got a valid configuration from DHCP, BOOTP or NV data */
- .config_capability = CFG_CAPS, /* attribute #2 config_capability */
- .config_control = 0x02, /* attribute #3 config_control: 0x02 means that the device shall obtain its interface configuration values via DHCP. */
- #if 2 != OPENER_ETHLINK_INSTANCE_CNT
- /* For the details where the physical_link_object path should point to, depending on the #
- * of Ethernet Link objects refer to Vol. 2, Section 5-4.3.2.4 "Physical Link Object". */
- .physical_link_object = { /* attribute #4 physical link object */
- 2, /* PathSize in 16 Bit chunks */
- CIP_ETHERNETLINK_CLASS_CODE, /* Class Code */
- OPENER_ETHLINK_INSTANCE_CNT, /* Instance # */
- 0 /* Attribute # (not used as this is the EPATH to the EthernetLink object)*/
- },
- #else
- .physical_link_object = { /* attribute #4 physical link object */
- 0, /* PathSize in 16 Bit chunks */
- 0, /* Class Code */
- 0, /* Instance # */
- 0 /* Attribute # */
- },
- #endif /* #if OPENER_ETHLINK_INSTANCE_CNT != 2 */
- .interface_configuration = { /* attribute #5 interface_configuration */
- 0, /* IP address */
- 0, /* NetworkMask */
- 0, /* Gateway */
- 0, /* NameServer */
- 0, /* NameServer2 */
- { /* DomainName */
- 0, NULL,
- }
- },
- .hostname = { /* attribute #6 hostname */
- 0,
- NULL
- },
- .mcast_ttl_value = 1, /* attribute #8 mcast TTL value */
- .mcast_config = { /* attribute #9 multicast configuration */
- 0, /* use the default allocation algorithm */
- 0, /* reserved */
- 1, /* we currently use only one multicast address */
- 0 /* the multicast address will be allocated on IP address configuration */
- },
- .select_acd = false,
- .encapsulation_inactivity_timeout = 120 /* attribute #13 encapsulation_inactivity_timeout, use a default value of 120 */
- };
- /************** Static Functions *********************************/
- #if defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && \
- 0 != OPENER_TCPIP_IFACE_CFG_SETTABLE
- /** Check for pb being an alphanumerical character
- *
- * Is slow but avoids issues with the locale if we're NOT in the 'C' locale.
- */
- static bool isalnum_c(const EipByte byte) {
- return
- ('a' <= byte && byte <= 'z') ||
- ('A' <= byte && byte <= 'Z') ||
- ('0' <= byte && byte <= '9');
- }
- /** Check passed string to conform to the rules for host name labels
- *
- * @param label pointer to the label string to check
- * @return true if label is valid
- *
- * A host name label is a string of length 1 to 63 characters with
- * the characters of the string conforming to this rules:
- * - 1st character: [A-Za-z0-9]
- * - next character: [-A-Za-z0-9]
- * - last character: [A-Za-z0-9]
- * The minimum length of 1 is checked but not the maximum length
- * that has already been enforced on data reception.
- */
- static bool IsValidNameLabel(const EipByte *label) {
- if (!isalnum_c(*label) ) {
- return false;
- }
- ++label;
- while ('\0' != *label && (isalnum_c(*label) || '-' == *label) ) {
- ++label;
- }
- return ('\0' == *label && '-' != label[-1]);
- }
- /** Check if domain is a valid domain
- *
- * @param p_domain pointer to domain string to check
- * @return true if domain is valid
- *
- * We check here for domain names that are part of a valid host name.
- * - Do not allow leading or trailing dots.
- * - Also a single '.' (the root domain) is not allowed.
- * - A complete numeric domain is accepted even if it should not.
- * - IDN domain names are not supported. Any IDN domain names must
- * be converted to punycode (see https://www.punycoder.com/) by
- * the user in advance.
- */
- static bool IsValidDomain(EipByte *domain) {
- bool status = true;
- OPENER_TRACE_INFO("Enter '%s'->", domain);
- if ('.' == *domain) { /* Forbid leading dot */
- return false;
- }
- EipByte *dot = (EipByte *)strchr( (char *)domain, '.' );
- if (dot) {
- bool rc;
- *dot = '\0';
- status &= rc = IsValidNameLabel(domain);
- OPENER_TRACE_INFO("Checked %d '%s'\n", rc, domain);
- if ('\0' != dot[1]) {
- status &= IsValidDomain(dot + 1);
- }
- else { /* Forbid trailing dot */
- status = false;
- }
- *dot = '.';
- }
- else {
- status = IsValidNameLabel(domain);
- OPENER_TRACE_INFO("Check end %d '%s'\n", status, domain);
- }
- return status;
- }
- /** Check if an IP address is a valid network mask
- *
- * @param netmask network mask in network byte order
- * @return valid status
- *
- * Check if it is a valid network mask pattern. The pattern 0xffffffff and
- * 0x00000000 are considered as invalid.
- */
- static bool IsValidNetmask(in_addr_t netmask) {
- in_addr_t v = ntohl(netmask);
- v = ~v; /* Create the host mask */
- ++v; /* This must be a power of 2 then */
- bool valid = v && !(v & (v - 1) ); /* Check if it is a power of 2 */
- return valid && (INADDR_BROADCAST != netmask);
- }
- /** Check if an IP address is in one of the network classes A, B or C
- *
- * @param ip_addr IP address in network byte order
- * @return status
- *
- * Check if the IP address belongs to the network classes A, B or C.
- */
- static bool IsInClassAbc(in_addr_t ip_addr) {
- in_addr_t ip = ntohl(ip_addr);
- return IN_CLASSA(ip) || IN_CLASSB(ip) || IN_CLASSC(ip);
- }
- /** Check if an IP address is on the loopback network
- *
- * @param ip_addr IP address in network byte order
- * @return status
- *
- * Check if the IP address belongs to the loopback network
- * 127.0.0.0 - 127.255.255.255.
- */
- static bool IsOnLoopbackNetwork(in_addr_t ip_addr) {
- in_addr_t ip = ntohl(ip_addr);
- return (ip & IN_CLASSA_NET) == (INADDR_LOOPBACK & IN_CLASSA_NET);
- }
- /** Check if an IP address is either the network or the broadcast address
- *
- * @param ip_addr IP address in network byte order
- * @param net_mask network mask in network byte order
- * @return status
- *
- * Check if an IP address is either the network or the broadcast address.
- * In this case it is not a valid IP address for a host.
- * This check is endian agnostic.
- */
- static bool IsNetworkOrBroadcastIp(in_addr_t ip_addr,
- in_addr_t net_mask) {
- return ( (ip_addr & net_mask) == ip_addr ) || /* is network address */
- ( (ip_addr | ~net_mask) == ip_addr ); /* is broadcast address */
- }
- /** Check the Interface configuration being valid according to EIP specification
- *
- * In Vol. 2 the "Table 5-4.3 Instance Attributes" provides some information
- * which checks should be carried out on the Interface configuration's IP
- * addresses. Also there are some hints in the
- * Figure 5-4.1 "Diagram Showing the Behavior of the TCP/IP Object".
- *
- * The following checks may carried out on the IP addresses:
- * - N0: IP is not 0 aka. INADDR_ANY
- * - MASK: IP is a valid network mask
- * - ABC: IP is in class A, B or C
- * - NLCL: IP is not localhost aka. INADDR_LOOPBACK
- * - NB: IP is neither network or broadcast address (using network_mask)
- *
- * This is the table which checks are applied to what IP:
- * N0 | MASK | ABC | NLCL | NB | IP address
- * + | - | + | + | + | ip_address
- * - | + | - | - | - | network_mask
- * - | - | + | + | + | gateway
- * - | - | + | - | - | name_server / name_server_2
- * A configured gateway must be reachable according to the network mask.
- */
- static bool IsValidNetworkConfig(const CipTcpIpInterfaceConfiguration *if_cfg) {
- if (INADDR_ANY == ntohl(if_cfg->ip_address) ) { /* N0 */
- return false;
- }
- if (INADDR_ANY != ntohl(if_cfg->network_mask) && /* MASK */
- !IsValidNetmask(if_cfg->network_mask) ) {
- return false;
- }
- if (!IsInClassAbc(if_cfg->ip_address) || /* ABC */
- !IsInClassAbc(if_cfg->gateway) ||
- !IsInClassAbc(if_cfg->name_server) ||
- !IsInClassAbc(if_cfg->name_server_2) ) {
- return false;
- }
- if (IsOnLoopbackNetwork(if_cfg->ip_address) || /* NLCL */
- IsOnLoopbackNetwork(if_cfg->gateway) ) {
- return false;
- }
- /* Check NB */
- if (IsNetworkOrBroadcastIp(if_cfg->ip_address, if_cfg->network_mask) ||
- (INADDR_ANY != ntohl(if_cfg->gateway) &&
- IsNetworkOrBroadcastIp(if_cfg->gateway, if_cfg->network_mask) ) ) {
- return false;
- }
- if (INADDR_ANY != ntohl(if_cfg->gateway) &&
- INADDR_ANY != ntohl(if_cfg->network_mask) ) {
- /* gateway is configured. Check if it is reachable. */
- if ( (if_cfg->network_mask & if_cfg->ip_address) !=
- (if_cfg->network_mask & if_cfg->gateway) ) {
- return false;
- }
- }
- return true;
- }
- static bool IsIOConnectionActive(void) {
- DoublyLinkedListNode *node = connection_list.first;
- while (NULL != node) {
- CipConnectionObject *connection = node->data;
- if (ConnectionObjectIsTypeIOConnection(connection) &&
- kConnectionObjectStateTimedOut !=
- ConnectionObjectGetState(connection) ) {
- /* An IO connection is present but is only considered active
- * if it is NOT in timeout state. */
- return true;
- }
- node = node->next;
- }
- return false;
- }
- #endif /* defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && 0 != OPENER_TCPIP_IFACE_CFG_SETTABLE*/
- static CipUsint dummy_data_field = 0; /**< dummy data fiel to provide non-null data pointers for attributes without data fields */
- /************** Functions ****************************************/
- void EncodeCipTcpIpInterfaceConfiguration(const void *const data,
- ENIPMessage *const outgoing_message)
- {
- CipTcpIpInterfaceConfiguration *
- tcp_ip_network_interface_configuration =
- (CipTcpIpInterfaceConfiguration *) data;
- AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->ip_address),
- outgoing_message);
- AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->network_mask),
- outgoing_message);
- AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->gateway),
- outgoing_message);
- AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->name_server),
- outgoing_message);
- AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->name_server_2),
- outgoing_message);
- EncodeCipString(&(tcp_ip_network_interface_configuration->domain_name),
- outgoing_message);
- }
- void EncodeCipTcpIpMulticastConfiguration(const void *const data,
- ENIPMessage *const outgoing_message) {
- EncodeCipUsint(&(g_tcpip.mcast_config.alloc_control), outgoing_message);
- EncodeCipUsint(&(g_tcpip.mcast_config.reserved_shall_be_zero),
- outgoing_message);
- EncodeCipUint(&(g_tcpip.mcast_config.number_of_allocated_multicast_addresses),
- outgoing_message);
- CipUdint multicast_address = ntohl(
- g_tcpip.mcast_config.starting_multicast_address);
- EncodeCipUdint(&multicast_address, outgoing_message);
- }
- void EncodeSafetyNetworkNumber(const void *const data,
- ENIPMessage *const outgoing_message) {
- FillNextNMessageOctetsWithValueAndMoveToNextPosition(0, 6, outgoing_message);
- }
- void EncodeCipLastConflictDetected(const void *const data,
- ENIPMessage *const outgoing_message) {
- const size_t kAttribute11Size = sizeof(CipUsint) + 6 * sizeof(CipUsint) + 28 *
- sizeof(CipUsint);
- OPENER_ASSERT(kAttribute11Size == 35);
- FillNextNMessageOctetsWithValueAndMoveToNextPosition(0,
- kAttribute11Size,
- outgoing_message);
- }
- int DecodeTcpIpInterfaceConfigurationControl( /* Attribute 3 */
- CipDword *const data,
- const CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- int number_of_decoded_bytes = -1;
- CipDword configuration_control_received = GetDintFromMessage(
- &(message_router_request->data));
- if ((configuration_control_received & kTcpipCfgCtrlMethodMask) >= 0x03
- || (configuration_control_received & ~kTcpipCfgCtrlMethodMask)) {
- message_router_response->general_status =
- kCipErrorInvalidAttributeValue;
- } else {
- /* Set reserved bits to zero on reception. */
- configuration_control_received &= (kTcpipCfgCtrlMethodMask
- | kTcpipCfgCtrlDnsEnable);
- *data = configuration_control_received;
- number_of_decoded_bytes = 4;
- message_router_response->general_status = kCipErrorSuccess;
- }
- return number_of_decoded_bytes;
- }
- #if defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && \
- 0 != OPENER_TCPIP_IFACE_CFG_SETTABLE
- int DecodeCipTcpIpInterfaceConfiguration( /* Attribute 5 */
- CipTcpIpInterfaceConfiguration *const data, //kCipUdintUdintUdintUdintUdintString
- const CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- int number_of_decoded_bytes = -1;
- CipTcpIpInterfaceConfiguration if_cfg;
- CipUdint tmp_ip;
- if (IsIOConnectionActive()) {
- message_router_response->general_status = kCipErrorDeviceStateConflict;
- return number_of_decoded_bytes;
- }
- if (kTcpipCfgCtrlStaticIp
- != (g_tcpip.config_control & kTcpipCfgCtrlMethodMask)) {
- message_router_response->general_status = kCipErrorObjectStateConflict;
- return number_of_decoded_bytes;
- }
- memset(&if_cfg, 0, sizeof if_cfg);
- tmp_ip = GetUdintFromMessage(&(message_router_request->data));
- if_cfg.ip_address = htonl(tmp_ip);
- tmp_ip = GetUdintFromMessage(&(message_router_request->data));
- if_cfg.network_mask = htonl(tmp_ip);
- tmp_ip = GetUdintFromMessage(&(message_router_request->data));
- if_cfg.gateway = htonl(tmp_ip);
- tmp_ip = GetUdintFromMessage(&(message_router_request->data));
- if_cfg.name_server = htonl(tmp_ip);
- tmp_ip = GetUdintFromMessage(&(message_router_request->data));
- if_cfg.name_server_2 = htonl(tmp_ip);
- CipUint domain_name_length = GetUintFromMessage(
- &(message_router_request->data));
- if (domain_name_length > 48) { /* see Vol. 2, Table 5-4.3 Instance Attributes */
- message_router_response->general_status = kCipErrorTooMuchData;
- return number_of_decoded_bytes;
- }
- SetCipStringByData(&if_cfg.domain_name, domain_name_length,
- message_router_request->data);
- domain_name_length = (domain_name_length + 1) & (~0x0001u); /* Align for possible pad byte */
- OPENER_TRACE_INFO("Domain: ds %hu '%s'\n",
- domain_name_length,
- if_cfg.domain_name.string);
- if (!IsValidNetworkConfig(&if_cfg)
- || (domain_name_length > 0
- && !IsValidDomain(if_cfg.domain_name.string))) {
- message_router_response->general_status =
- kCipErrorInvalidAttributeValue;
- return number_of_decoded_bytes;
- }
- *data = if_cfg; //write data to attribute
- number_of_decoded_bytes = 20 + domain_name_length;
- /* Tell that this configuration change becomes active after a reset */
- g_tcpip.status |= kTcpipStatusIfaceCfgPend;
- message_router_response->general_status = kCipErrorSuccess;
- return number_of_decoded_bytes;
- }
- int DecodeCipTcpIpInterfaceHostName( /* Attribute 6 */
- CipString *const data,
- const CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- int number_of_decoded_bytes = -1;
- CipString tmp_host_name = {
- .length = 0u,
- .string = NULL
- };
- CipUint host_name_length =
- GetUintFromMessage(&(message_router_request->data) );
- if (host_name_length > 64) { /* see RFC 1123 on more details */
- message_router_response->general_status = kCipErrorTooMuchData;
- return number_of_decoded_bytes;
- }
- SetCipStringByData(&tmp_host_name,
- host_name_length,
- message_router_request->data);
- host_name_length = (host_name_length + 1) & (~0x0001u); /* Align for possible pad byte */
- OPENER_TRACE_INFO("Host Name: ds %hu '%s'\n",
- host_name_length,
- tmp_host_name.string);
- if (!IsValidNameLabel(tmp_host_name.string) ) {
- message_router_response->general_status =
- kCipErrorInvalidAttributeValue;
- return number_of_decoded_bytes;
- }
- *data = tmp_host_name; //write data to attribute
- /* Tell that this configuration change becomes active after a reset */
- g_tcpip.status |= kTcpipStatusIfaceCfgPend;
- message_router_response->general_status = kCipErrorSuccess;
- return number_of_decoded_bytes;
- }
- #endif /* defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && 0 != OPENER_TCPIP_IFACE_CFG_SETTABLE*/
- int DecodeCipTcpIpInterfaceEncapsulationInactivityTimeout( /* Attribute 13 */
- CipUint *const data,
- const CipMessageRouterRequest *const message_router_request,
- CipMessageRouterResponse *const message_router_response) {
- int number_of_decoded_bytes = -1;
- CipUint inactivity_timeout_received = GetUintFromMessage(
- &(message_router_request->data));
- if (inactivity_timeout_received > 3600) {
- message_router_response->general_status =
- kCipErrorInvalidAttributeValue;
- } else {
- *data = inactivity_timeout_received;
- message_router_response->general_status = kCipErrorSuccess;
- number_of_decoded_bytes = 2;
- }
- return number_of_decoded_bytes;
- }
- EipStatus CipTcpIpInterfaceInit() {
- CipClass *tcp_ip_class = NULL;
- if ( ( tcp_ip_class = CreateCipClass(kCipTcpIpInterfaceClassCode, /* class code */
- 0, /* # class attributes */
- 7, /* # highest class attribute number */
- 2, /* # class services */
- 13, /* # instance attributes */
- 13, /* # highest instance attribute number */
- 3, /* # instance services */
- 1, /* # instances */
- "TCP/IP interface", 4, /* # class revision */
- NULL /* # function pointer for initialization */
- ) ) == 0 ) {
- return kEipStatusError;
- }
- CipInstance *instance = GetCipInstance(tcp_ip_class, 1); /* bind attributes to the instance #1 that was created above */
- InsertAttribute(instance,
- 1,
- kCipDword,
- EncodeCipDword,
- NULL,
- &g_tcpip.status,
- kGetableSingleAndAll);
- InsertAttribute(instance,
- 2,
- kCipDword,
- EncodeCipDword,
- NULL,
- &g_tcpip.config_capability,
- kGetableSingleAndAll);
- InsertAttribute(instance,
- 3,
- kCipDword,
- EncodeCipDword,
- DecodeTcpIpInterfaceConfigurationControl,
- &g_tcpip.config_control,
- kSetAndGetAble | kNvDataFunc | IFACE_CFG_SET_MODE );
- InsertAttribute(instance,
- 4,
- kCipEpath,
- EncodeCipEPath,
- NULL,
- &g_tcpip.physical_link_object,
- kGetableSingleAndAll);
- #if defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && \
- 0 != OPENER_TCPIP_IFACE_CFG_SETTABLE
- InsertAttribute(instance,
- 5,
- kCipUdintUdintUdintUdintUdintString,
- EncodeCipTcpIpInterfaceConfiguration,
- DecodeCipTcpIpInterfaceConfiguration,
- &g_tcpip.interface_configuration,
- kGetableSingleAndAll | kNvDataFunc | IFACE_CFG_SET_MODE);
- InsertAttribute(instance,
- 6,
- kCipString,
- EncodeCipString,
- DecodeCipTcpIpInterfaceHostName,
- &g_tcpip.hostname,
- kGetableSingleAndAll | kNvDataFunc | IFACE_CFG_SET_MODE);
- #else
- InsertAttribute(instance,
- 5,
- kCipUdintUdintUdintUdintUdintString,
- EncodeCipTcpIpInterfaceConfiguration,
- NULL, //not settable
- &g_tcpip.interface_configuration,
- kGetableSingleAndAll | kNvDataFunc | IFACE_CFG_SET_MODE);
- InsertAttribute(instance,
- 6,
- kCipString,
- EncodeCipString,
- NULL, //not settable
- &g_tcpip.hostname,
- kGetableSingleAndAll | kNvDataFunc | IFACE_CFG_SET_MODE);
- #endif /* defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && 0 != OPENER_TCPIP_IFACE_CFG_SETTABLE*/
- InsertAttribute(instance,
- 7,
- kCipAny,
- EncodeSafetyNetworkNumber,
- NULL,
- &dummy_data_field,
- kGetableAllDummy);
- InsertAttribute(instance,
- 8,
- kCipUsint,
- EncodeCipUsint,
- NULL,
- &g_tcpip.mcast_ttl_value,
- kGetableSingleAndAll);
- InsertAttribute(instance,
- 9,
- kCipAny,
- EncodeCipTcpIpMulticastConfiguration,
- NULL,
- &g_tcpip.mcast_config,
- kGetableSingleAndAll);
- InsertAttribute(instance,
- 10,
- kCipBool,
- EncodeCipBool,
- NULL,
- &g_tcpip.select_acd,
- kGetableAllDummy);
- InsertAttribute(instance,
- 11,
- kCipBool,
- EncodeCipLastConflictDetected,
- NULL,
- &dummy_data_field,
- kGetableAllDummy);
- InsertAttribute(instance,
- 12,
- kCipBool,
- EncodeCipBool,
- NULL,
- &dummy_data_field, kGetableAllDummy);
- InsertAttribute(instance,
- 13,
- kCipUint,
- EncodeCipUint,
- DecodeCipTcpIpInterfaceEncapsulationInactivityTimeout,
- &g_tcpip.encapsulation_inactivity_timeout,
- kSetAndGetAble | kNvDataFunc);
- InsertService(tcp_ip_class, kGetAttributeSingle,
- &GetAttributeSingle,
- "GetAttributeSingle");
- InsertService(tcp_ip_class, kGetAttributeAll, &GetAttributeAll,
- "GetAttributeAll");
- InsertService(tcp_ip_class, kSetAttributeSingle,
- &SetAttributeSingle,
- "SetAttributeSingle");
- return kEipStatusOk;
- }
- void ShutdownTcpIpInterface(void) {
- /*Only free the resources if they are initialized */
- if (NULL != g_tcpip.hostname.string) {
- CipFree(g_tcpip.hostname.string);
- g_tcpip.hostname.string = NULL;
- }
- if (NULL != g_tcpip.interface_configuration.domain_name.string) {
- CipFree(g_tcpip.interface_configuration.domain_name.string);
- g_tcpip.interface_configuration.domain_name.string = NULL;
- }
- }
- /**
- * This function calculates the multicast base address to be used for CIP
- * connections from the current IP setting. The algorithm is implemented
- * according to CIP spec Volume 2,
- * section 3-5.3 "Multicast Address Allocation for EtherNet/IP"
- */
- void CipTcpIpCalculateMulticastIp(CipTcpIpObject *const tcpip) {
- /* Multicast base address according to spec: 239.192.1.0 */
- static const CipUdint cip_mcast_base_addr = 0xEFC00100;
- /* Calculate the CIP multicast address. The multicast address is calculated, not input */
- CipUdint host_id = ntohl(tcpip->interface_configuration.ip_address) &
- ~ntohl(tcpip->interface_configuration.network_mask);
- host_id -= 1;
- host_id &= 0x3ff;
- tcpip->mcast_config.starting_multicast_address =
- htonl(cip_mcast_base_addr + (host_id << 5) );
- }
- EipUint16 GetEncapsulationInactivityTimeout(CipInstance *instance) {
- CipAttributeStruct *attribute = GetCipAttribute(instance, 13);
- OPENER_ASSERT(NULL != attribute);
- CipUint *data = (CipUint *) attribute->data;
- EipUint16 encapsulation_inactivity_timeout = *data;
- return encapsulation_inactivity_timeout;
- }
|