EipStatus SendUdpData(struct sockaddr_in *pa_pstAddr, int pa_nSockFd, EipUint8*pa_acData, EipUint16 pa_nDataLength) { int sentlength; sentlength = sendto(pa_nSockFd, (char *) pa_acData, pa_nDataLength, 0, (struct sockaddr *) pa_pstAddr, sizeof(*pa_pstAddr)); if (sentlength < 0) { OPENER_TRACE_ERR("networkhandler: error with sendto in sendUDPData: %s\n", strerror(errno)); return kEipStatusError; } else if (sentlength != pa_nDataLength) { OPENER_TRACE_WARN("not all data was sent in sendUDPData, sent %d of %d\n", sentlength, pa_nDataLength); return kEipStatusError; } else return kEipStatusError; }
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; }
/* @brief Creates Common Packet Format structure out of data. * @param data pointer to data which need to be structured. * @param data_length length of data in pa_Data. * @param common_packet_format_data pointer to structure of CPF data item. * * @return kEipStatusOk .. success * kEipStatusError .. error */ EipStatus CreateCommonPacketFormatStructure( EipUint8 *data, int data_length, CipCommonPacketFormatData *common_packet_format_data) { common_packet_format_data->address_info_item[0].type_id = 0; common_packet_format_data->address_info_item[1].type_id = 0; int length_count = 0; common_packet_format_data->item_count = GetIntFromMessage(&data); length_count += 2; if (common_packet_format_data->item_count >= 1) { common_packet_format_data->address_item.type_id = GetIntFromMessage(&data); common_packet_format_data->address_item.length = GetIntFromMessage(&data); length_count += 4; if (common_packet_format_data->address_item.length >= 4) { common_packet_format_data->address_item.data.connection_identifier = GetDintFromMessage(&data); length_count += 4; } if (common_packet_format_data->address_item.length == 8) { common_packet_format_data->address_item.data.sequence_number = GetDintFromMessage(&data); length_count += 4; } } if (common_packet_format_data->item_count >= 2) { common_packet_format_data->data_item.type_id = GetIntFromMessage(&data); common_packet_format_data->data_item.length = GetIntFromMessage(&data); common_packet_format_data->data_item.data = data; data += common_packet_format_data->data_item.length; length_count += (4 + common_packet_format_data->data_item.length); } for (int j = 0; j < (common_packet_format_data->item_count - 2); j++) /* TODO there needs to be a limit check here???*/ { common_packet_format_data->address_info_item[j].type_id = GetIntFromMessage( &data); length_count += 2; if ((common_packet_format_data->address_info_item[j].type_id == kCipItemIdSocketAddressInfoOriginatorToTarget) || (common_packet_format_data->address_info_item[j].type_id == kCipItemIdSocketAddressInfoTargetToOriginator)) { common_packet_format_data->address_info_item[j].length = GetIntFromMessage(&data); common_packet_format_data->address_info_item[j].sin_family = GetIntFromMessage(&data); common_packet_format_data->address_info_item[j].sin_port = GetIntFromMessage(&data); common_packet_format_data->address_info_item[j].sin_addr = GetDintFromMessage(&data); for (int i = 0; i < 8; i++) { common_packet_format_data->address_info_item[j].nasin_zero[i] = *data; data++; } length_count += 18; } else { /* no sockaddr item found */ common_packet_format_data->address_info_item[j].type_id = 0; /* mark as not set */ data -= 2; } } /* set the addressInfoItems to not set if they were not received */ if (common_packet_format_data->item_count < 4) { common_packet_format_data->address_info_item[1].type_id = 0; if (common_packet_format_data->item_count < 3) { common_packet_format_data->address_info_item[0].type_id = 0; } } if (length_count == data_length) { /* length of data is equal to length of Addr and length of Data */ return kEipStatusOk; } else { OPENER_TRACE_WARN( "something is wrong with the length in Message Router @ CreateCommonPacketFormatStructure\n"); if (common_packet_format_data->item_count > 2) { /* there is an optional packet in data stream which is not sockaddr item */ return kEipStatusOk; } else { /* something with the length was wrong */ return kEipStatusError; } } }
EIP_STATUS setAssemblyAttributeSingle(S_CIP_Instance * pa_pstInstance, S_CIP_MR_Request * pa_pstMRRequest, S_CIP_MR_Response * pa_pstMRResponse) { EIP_UINT8 * acReqData; S_CIP_attribute_struct * p; OPENER_TRACE_INFO(" setAttribute %d\n", pa_pstMRRequest->RequestPath.AttributNr); acReqData = pa_pstMRRequest->Data; pa_pstMRResponse->DataLength = 0; pa_pstMRResponse->ReplyService = (0x80 | pa_pstMRRequest->Service); pa_pstMRResponse->GeneralStatus = CIP_ERROR_ATTRIBUTE_NOT_SUPPORTED; pa_pstMRResponse->SizeofAdditionalStatus = 0; p = getAttribute(pa_pstInstance, pa_pstMRRequest->RequestPath.AttributNr); if((p != 0) && (3 == pa_pstMRRequest->RequestPath.AttributNr)) { if(p->pt2data != 0) { S_CIP_Byte_Array * pacData = (S_CIP_Byte_Array *) p->pt2data; //TODO: check for ATTRIBUTE_SET/GETABLE MASK if(true == isConnectedOutputAssembly(pa_pstInstance->nInstanceNr)) { OPENER_TRACE_WARN("Assembly AssemblyAttributeSingle: received data for connected output assembly\n\r"); pa_pstMRResponse->GeneralStatus = CIP_ERROR_ATTRIBUTE_NOT_SETTABLE; } else { if(pa_pstMRRequest->DataLength < pacData->len) { OPENER_TRACE_INFO("Assembly setAssemblyAttributeSingle: not enough data received.\r\n"); pa_pstMRResponse->GeneralStatus = CIP_ERROR_NOT_ENOUGH_DATA; } else { if(pa_pstMRRequest->DataLength > pacData->len) { OPENER_TRACE_INFO("Assembly setAssemblyAttributeSingle: too much data received.\r\n"); pa_pstMRResponse->GeneralStatus = CIP_ERROR_TOO_MUCH_DATA; } else { memcpy(pacData->Data, acReqData, pacData->len); if(IApp_AfterAssemblyDataReceived(pa_pstInstance) != EIP_OK) { /* punt early without updating the status... though I don't know * how much this helps us here, as the attribute's data has already * been overwritten. * * however this is the task of the application side which will * take the data. In addition we have to inform the sender that the * data was not ok. */ pa_pstMRResponse->GeneralStatus = CIP_ERROR_INVALID_ATTRIBUTE_VALUE; } else { pa_pstMRResponse->GeneralStatus = CIP_ERROR_SUCCESS; } } } } } else { /* the attribute was zero we are a heartbeat assembly */ pa_pstMRResponse->GeneralStatus = CIP_ERROR_TOO_MUCH_DATA; } } return EIP_OK_SEND; }
EipStatus handleDataOnTCPSocket(int pa_nSocket) { EipUint8 *rxp; long nCheckVal; size_t unDataSize; long nDataSent; int nRemainingBytes = 0; /* We will handle just one EIP packet here the rest is done by the select * method which will inform us if more data is available in the socket because of the current implementation of the main loop this may not be the fastest way and a loop here with a non blocking socket would better fit*/ /*Check how many data is here -- read the first four bytes from the connection */ nCheckVal = recv(pa_nSocket, g_ethernet_communciation_buffer, 4, 0); /*TODO we may have to set the socket to a non blocking socket */ if (nCheckVal == 0) { OPENER_TRACE_ERR("networkhandler: connection closed by client: %s\n", strerror(errno)); return kEipStatusError; } if (nCheckVal < 0) { OPENER_TRACE_ERR("networkhandler: error on recv: %s\n", strerror(errno)); return kEipStatusError; } rxp = &g_ethernet_communciation_buffer[2]; /* at this place EIP stores the data length */ unDataSize = GetIntFromMessage(&rxp) + ENCAPSULATION_HEADER_LENGTH - 4; /* -4 is for the 4 bytes we have already read*/ /* (NOTE this advances the buffer pointer) */ if (PC_OPENER_ETHERNET_BUFFER_SIZE - 4 < unDataSize) { /*TODO can this be handled in a better way?*/ OPENER_TRACE_ERR("too large packet received will be ignored, will drop the data\n"); /* Currently we will drop the whole packet */ nDataSent = PC_OPENER_ETHERNET_BUFFER_SIZE; do { nCheckVal = recv(pa_nSocket, g_ethernet_communciation_buffer, nDataSent, 0); if (nCheckVal == 0) /* got error or connection closed by client */ { OPENER_TRACE_ERR("networkhandler: connection closed by client: %s\n", strerror(errno)); return kEipStatusError; } if (nCheckVal < 0) { OPENER_TRACE_ERR("networkhandler: error on recv: %s\n", strerror(errno)); return kEipStatusError; } unDataSize -= nCheckVal; if ((unDataSize < PC_OPENER_ETHERNET_BUFFER_SIZE) && (unDataSize != 0)) { nDataSent = unDataSize; } } while (0 != unDataSize); /*TODO fragile end statement */ return kEipStatusOk; } nCheckVal = recv(pa_nSocket, &g_ethernet_communciation_buffer[4], unDataSize, 0); if (nCheckVal == 0) /* got error or connection closed by client */ { OPENER_TRACE_ERR("networkhandler: connection closed by client: %s\n", strerror(errno)); return kEipStatusError; } if (nCheckVal < 0) { OPENER_TRACE_ERR("networkhandler: error on recv: %s\n", strerror(errno)); return kEipStatusError; } if ((unsigned) nCheckVal == unDataSize) { /*we got the right amount of data */ unDataSize += 4; /*TODO handle partial packets*/ OPENER_TRACE_INFO("Data received on tcp:\n"); g_current_active_tcp_socket = pa_nSocket; nCheckVal = HandleReceivedExplictTcpData(pa_nSocket, g_ethernet_communciation_buffer, unDataSize, &nRemainingBytes); g_current_active_tcp_socket = -1; if (nRemainingBytes != 0) { OPENER_TRACE_WARN("Warning: received packet was to long: %d Bytes left!\n", nRemainingBytes); } if (nCheckVal > 0) { OPENER_TRACE_INFO("reply sent:\n"); nDataSent = send(pa_nSocket, (char *) g_ethernet_communciation_buffer, nCheckVal, 0); if (nDataSent != nCheckVal) { OPENER_TRACE_WARN("TCP response was not fully sent\n"); } } return kEipStatusOk; } else { /* we got a fragmented packet currently we cannot handle this will * for this we would need a network buffer per TCP socket * * However with typical packet sizes of EIP this should't be a big issue. */ /*TODO handle fragmented packets */ } return kEipStatusError; }