/** @brief Get the registered MessageRouter object corresponding to ClassID. * given a class ID, return a pointer to the registration node for that object * * @param class_id Class code to be searched for. * @return Pointer to registered message router object * NULL .. Class not registered */ CipMessageRouterObject *GetRegisteredObject(EipUint32 class_id) { CipMessageRouterObject *object = g_first_object; /* get pointer to head of class registration list */ while (NULL != object) /* for each entry in list*/ { OPENER_ASSERT(object->cip_class != NULL); if (object->cip_class->class_id == class_id) { return object; /* return registration node if it matches class ID*/ } object = object->next; } return NULL; }
void HandleIoConnectionTimeOut(ConnectionObject *connection_object) { ConnectionObject *next_non_control_master_connection; CheckIoConnectionEvent(connection_object->connection_path.connection_point[0], connection_object->connection_path.connection_point[1], kIoConnectionEventTimedOut); if (kRoutingTypeMulticastConnection == (connection_object->t_to_o_network_connection_parameter & kRoutingTypeMulticastConnection)) { switch (connection_object->instance_type) { case kConnectionTypeIoExclusiveOwner: CloseAllConnectionsForInputWithSameType( connection_object->connection_path.connection_point[1], kConnectionTypeIoInputOnly); CloseAllConnectionsForInputWithSameType( connection_object->connection_path.connection_point[1], kConnectionTypeIoListenOnly); break; case kConnectionTypeIoInputOnly: if (kEipInvalidSocket != connection_object->socket[kUdpCommuncationDirectionProducing]) { /* we are the controlling input only connection find a new controller*/ next_non_control_master_connection = GetNextNonControlMasterConnection( connection_object->connection_path.connection_point[1]); if (NULL != next_non_control_master_connection) { next_non_control_master_connection->socket[kUdpCommuncationDirectionProducing] = connection_object->socket[kUdpCommuncationDirectionProducing]; connection_object->socket[kUdpCommuncationDirectionProducing] = kEipInvalidSocket; next_non_control_master_connection->transmission_trigger_timer = connection_object->transmission_trigger_timer; } else { /* this was the last master connection close all listen only connections listening on the port */ CloseAllConnectionsForInputWithSameType( connection_object->connection_path.connection_point[1], kConnectionTypeIoListenOnly); } } break; default: break; } } OPENER_ASSERT(NULL != connection_object->connection_close_function); connection_object->connection_close_function(connection_object); }
void CipStackInit(const EipUint16 unique_connection_id) { EncapsulationInit(); /* The message router is the first CIP object be initialized!!! */ EipStatus eip_status = CipMessageRouterInit(); OPENER_ASSERT(kEipStatusOk == eip_status) eip_status = CipIdentityInit(); OPENER_ASSERT(kEipStatusOk == eip_status) eip_status = CipTcpIpInterfaceInit(); OPENER_ASSERT(kEipStatusOk == eip_status) eip_status = CipEthernetLinkInit(); OPENER_ASSERT(kEipStatusOk == eip_status) eip_status = ConnectionManagerInit(unique_connection_id); OPENER_ASSERT(kEipStatusOk == eip_status) eip_status = CipAssemblyInitialize(); OPENER_ASSERT(kEipStatusOk == eip_status) eip_status = CipQoSInit(); OPENER_ASSERT(kEipStatusOk == eip_status) /* the application has to be initialized at last */ eip_status = ApplicationInitialization(); OPENER_ASSERT(kEipStatusOk == eip_status) /* Shut up compiler warning with traces disabled */ (void) eip_status; }
/**** Implementation ****/ int EstablishIoConnction(ConnectionObject *connection_object, EipUint16 *extended_error) { int originator_to_target_connection_type, target_to_originator_connection_type; int eip_status = kEipStatusOk; CipAttributeStruct *attribute; /* currently we allow I/O connections only to assembly objects */ CipClass *assembly_class = GetCipClass(kCipAssemblyClassCode); /* we don't need to check for zero as this is handled in the connection path parsing */ CipInstance *instance = NULL; ConnectionObject *io_connection_object = GetIoConnectionForConnectionData( connection_object, extended_error); if (NULL == io_connection_object) { return kCipErrorConnectionFailure; } /* TODO add check for transport type trigger */ if (kConnectionTriggerTypeCyclicConnection != (io_connection_object->transport_type_class_trigger & kConnectionTriggerTypeProductionTriggerMask)) { if (256 == io_connection_object->production_inhibit_time) { /* there was no PIT segment in the connection path set PIT to one fourth of RPI */ io_connection_object->production_inhibit_time = ((EipUint16) (io_connection_object->t_to_o_requested_packet_interval) / 4000); } else { /* if production inhibit time has been provided it needs to be smaller than the RPI */ if (io_connection_object->production_inhibit_time > ((EipUint16) ((io_connection_object ->t_to_o_requested_packet_interval) / 1000))) { /* see section C-1.4.3.3 */ *extended_error = 0x111; /**< RPI not supported. Extended Error code deprecated */ return kCipErrorConnectionFailure; } } } /* set the connection call backs */ io_connection_object->connection_close_function = CloseIoConnection; io_connection_object->connection_timeout_function = HandleIoConnectionTimeOut; io_connection_object->connection_send_data_function = SendConnectedData; io_connection_object->connection_receive_data_function = HandleReceivedIoConnectionData; GeneralConnectionConfiguration(io_connection_object); originator_to_target_connection_type = (io_connection_object ->o_to_t_network_connection_parameter & 0x6000) >> 13; target_to_originator_connection_type = (io_connection_object ->t_to_o_network_connection_parameter & 0x6000) >> 13; if ((originator_to_target_connection_type == 0) && (target_to_originator_connection_type == 0)) { /* this indicates an re-configuration of the connection currently not supported and we should not come here as this is handled in the forwardopen function*/ } else { int producing_index = 0; int data_size; int diff_size; int is_heartbeat; if ((originator_to_target_connection_type != 0) && (target_to_originator_connection_type != 0)) { /* we have a producing and consuming connection*/ producing_index = 1; } io_connection_object->consuming_instance = 0; io_connection_object->consumed_connection_path_length = 0; io_connection_object->producing_instance = 0; io_connection_object->produced_connection_path_length = 0; if (originator_to_target_connection_type != 0) { /*setup consumer side*/ if (0 != (instance = GetCipInstance( assembly_class, io_connection_object->connection_path.connection_point[0]))) { /* consuming Connection Point is present */ io_connection_object->consuming_instance = instance; io_connection_object->consumed_connection_path_length = 6; io_connection_object->consumed_connection_path.path_size = 6; io_connection_object->consumed_connection_path.class_id = io_connection_object->connection_path.class_id; io_connection_object->consumed_connection_path.instance_number = io_connection_object->connection_path.connection_point[0]; io_connection_object->consumed_connection_path.attribute_number = 3; attribute = GetCipAttribute(instance, 3); OPENER_ASSERT(attribute != NULL); /* an assembly object should always have an attribute 3 */ data_size = io_connection_object->consumed_connection_size; diff_size = 0; is_heartbeat = (((CipByteArray *) attribute->data)->length == 0); if ((io_connection_object->transport_type_class_trigger & 0x0F) == 1) { /* class 1 connection */ data_size -= 2; /* remove 16-bit sequence count length */ diff_size += 2; } if ((kOpenerConsumedDataHasRunIdleHeader) &&(data_size > 0) && (!is_heartbeat)) { /* we only have an run idle header if it is not an heartbeat connection */ data_size -= 4; /* remove the 4 bytes needed for run/idle header */ diff_size += 4; } if (((CipByteArray *) attribute->data)->length != data_size) { /*wrong connection size */ connection_object->correct_originator_to_target_size = ((CipByteArray *) attribute->data)->length + diff_size; *extended_error = kConnectionManagerStatusCodeErrorInvalidOToTConnectionSize; return kCipErrorConnectionFailure; } } else { *extended_error = kConnectionManagerStatusCodeInvalidConsumingApllicationPath; return kCipErrorConnectionFailure; } } if (target_to_originator_connection_type != 0) { /*setup producer side*/ if (0 != (instance = GetCipInstance( assembly_class, io_connection_object->connection_path.connection_point[producing_index]))) { io_connection_object->producing_instance = instance; io_connection_object->produced_connection_path_length = 6; io_connection_object->produced_connection_path.path_size = 6; io_connection_object->produced_connection_path.class_id = io_connection_object->connection_path.class_id; io_connection_object->produced_connection_path.instance_number = io_connection_object->connection_path.connection_point[producing_index]; io_connection_object->produced_connection_path.attribute_number = 3; attribute = GetCipAttribute(instance, 3); OPENER_ASSERT(attribute != NULL); /* an assembly object should always have an attribute 3 */ data_size = io_connection_object->produced_connection_size; diff_size = 0; is_heartbeat = (((CipByteArray *) attribute->data)->length == 0); if ((io_connection_object->transport_type_class_trigger & 0x0F) == 1) { /* class 1 connection */ data_size -= 2; /* remove 16-bit sequence count length */ diff_size += 2; } if ((kOpenerProducedDataHasRunIdleHeader) &&(data_size > 0) && (!is_heartbeat)) { /* we only have an run idle header if it is not an heartbeat connection */ data_size -= 4; /* remove the 4 bytes needed for run/idle header */ diff_size += 4; } if (((CipByteArray *) attribute->data)->length != data_size) { /*wrong connection size*/ connection_object->correct_target_to_originator_size = ((CipByteArray *) attribute->data)->length + diff_size; *extended_error = kConnectionManagerStatusCodeErrorInvalidTToOConnectionSize; return kCipErrorConnectionFailure; } } else { *extended_error = kConnectionManagerStatusCodeInvalidProducingApplicationPath; return kCipErrorConnectionFailure; } } if (NULL != g_config_data_buffer) { /* config data has been sent with this forward open request */ *extended_error = HandleConfigData(assembly_class, io_connection_object); if (0 != *extended_error) { return kCipErrorConnectionFailure; } } eip_status = OpenCommunicationChannels(io_connection_object); if (kEipStatusOk != eip_status) { *extended_error = 0; /*TODO find out the correct extended error code*/ return eip_status; } } AddNewActiveConnection(io_connection_object); CheckIoConnectionEvent(io_connection_object->connection_path.connection_point[0], io_connection_object->connection_path.connection_point[1], kIoConnectionEventOpened); return eip_status; }