EipUint16 HandleConfigData(CipClass *assembly_class, ConnectionObject *connection_object) { EipUint16 connection_manager_status = 0; CipInstance *config_instance = GetCipInstance( assembly_class, connection_object->connection_path.connection_point[2]); if (0 != g_config_data_length) { if (ConnectionWithSameConfigPointExists( connection_object->connection_path.connection_point[2])) { /* there is a connected connection with the same config point * we have to have the same data as already present in the config point*/ CipByteArray *p = (CipByteArray *) GetCipAttribute(config_instance, 3) ->data; if (p->length != g_config_data_length) { connection_manager_status = kConnectionManagerStatusCodeErrorOwnershipConflict; } else { /*FIXME check if this is correct */ if (memcmp(p->data, g_config_data_buffer, g_config_data_length)) { connection_manager_status = kConnectionManagerStatusCodeErrorOwnershipConflict; } } } else { /* put the data on the configuration assembly object with the current design this can be done rather efficiently */ if (kEipStatusOk != NotifyAssemblyConnectedDataReceived(config_instance, g_config_data_buffer, g_config_data_length)) { OPENER_TRACE_WARN("Configuration data was invalid\n"); connection_manager_status = kConnectionManagerStatusCodeInvalidConfigurationApplicationPath; } } } return connection_manager_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; }
ShutdownTcpIpInterface(); /*no clear all the instances and classes */ DeleteAllClasses(); } EipStatus NotifyClass(const CipClass *RESTRICT const cip_class, CipMessageRouterRequest *const message_router_request, CipMessageRouterResponse *const message_router_response, struct sockaddr *originator_address, const int encapsulation_session) { /* find the instance: if instNr==0, the class is addressed, else find the instance */ EipUint16 instance_number = message_router_request->request_path.instance_number; /* get the instance number */ CipInstance *instance = GetCipInstance(cip_class, instance_number); /* look up the instance (note that if inst==0 this will be the class itself) */ if (instance) /* if instance is found */ { OPENER_TRACE_INFO("notify: found instance %d%s\n", instance_number, instance_number == 0 ? " (class object)" : ""); CipServiceStruct *service = instance->cip_class->services; /* get pointer to array of services */ if (NULL != service) /* if services are defined */ { for (size_t i = 0; i < instance->cip_class->number_of_services; i++) /* seach the services list */ { if (message_router_request->service == service->service_number) /* if match is found */ { /* call the service, and return what it returns */ OPENER_TRACE_INFO("notify: calling %s service\n", service->name);