int arf_decode_apdu( uint8_t * apdu, unsigned apdu_len, uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data) { int len = 0; unsigned offset = 0; if (!apdu) return -1; /* optional checking - most likely was already done prior to this call */ if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) return -1; /* apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); */ *invoke_id = apdu[2]; /* invoke id - filled in by net layer */ if (apdu[3] != SERVICE_CONFIRMED_ATOMIC_READ_FILE) return -1; offset = 4; if (apdu_len > offset) { len = arf_decode_service_request(&apdu[offset], apdu_len - offset, data); } return len; }
/* when the request was sent */ uint32_t bacfile_instance_from_tsm( uint8_t invokeID) { BACNET_NPDU_DATA npdu_data = { 0 }; /* dummy for getting npdu length */ BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 }; uint8_t service_choice = 0; uint8_t *service_request = NULL; uint16_t service_request_len = 0; BACNET_ADDRESS dest; /* where the original packet was destined */ uint8_t apdu[MAX_PDU] = { 0 }; /* original APDU packet */ uint16_t apdu_len = 0; /* original APDU packet length */ int len = 0; /* apdu header length */ BACNET_ATOMIC_READ_FILE_DATA data = { 0 }; uint32_t object_instance = BACNET_MAX_INSTANCE + 1; /* return value */ bool found = false; found = tsm_get_transaction_pdu(invokeID, &dest, &npdu_data, &apdu[0], &apdu_len); if (found) { if (!npdu_data.network_layer_message && npdu_data.data_expecting_reply && (apdu[0] == PDU_TYPE_CONFIRMED_SERVICE_REQUEST)) { len = apdu_decode_confirmed_service_request(&apdu[0], apdu_len, &service_data, &service_choice, &service_request, &service_request_len); if (service_choice == SERVICE_CONFIRMED_ATOMIC_READ_FILE) { len = arf_decode_service_request(service_request, service_request_len, &data); if (len > 0) { if (data.object_type == OBJECT_FILE) object_instance = data.object_instance; } } } } return object_instance; }
void handler_atomic_read_file( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_ATOMIC_READ_FILE_DATA data; int len = 0; int pdu_len = 0; bool error = false; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; #if PRINT_ENABLED fprintf(stderr, "Received Atomic-Read-File Request!\n"); #endif /* encode the NPDU portion of the packet */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); if (service_data->segmented_message) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "ARF: Segmented Message. Sending Abort!\n"); #endif goto ARF_ABORT; } len = arf_decode_service_request(service_request, service_len, &data); /* bad decoding - send an abort */ if (len < 0) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); #if PRINT_ENABLED fprintf(stderr, "Bad Encoding. Sending Abort!\n"); #endif goto ARF_ABORT; } if (data.object_type == OBJECT_FILE) { if (!bacfile_valid_instance(data.object_instance)) { error = true; } else if (data.access == FILE_STREAM_ACCESS) { if (data.type.stream.requestedOctetCount < octetstring_capacity(&data.fileData[0])) { if (bacfile_read_stream_data(&data)) { #if PRINT_ENABLED fprintf(stderr, "ARF: Stream offset %d, %d octets.\n", data.type.stream.fileStartPosition, data.type.stream.requestedOctetCount); #endif len = arf_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, &data); } else { error = true; error_class = ERROR_CLASS_OBJECT; error_code = ERROR_CODE_FILE_ACCESS_DENIED; } } else { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "Too Big To Send (%d >= %d). Sending Abort!\n", data.type.stream.requestedOctetCount, octetstring_capacity(&data.fileData[0])); #endif } } else if (data.access == FILE_RECORD_ACCESS) { if (data.type.record.fileStartRecord >= BACNET_READ_FILE_RECORD_COUNT) { error_class = ERROR_CLASS_SERVICES; error_code = ERROR_CODE_INVALID_FILE_START_POSITION; error = true; } else if (bacfile_read_stream_data(&data)) { #if PRINT_ENABLED fprintf(stderr, "ARF: fileStartRecord %d, %u RecordCount.\n", data.type.record.fileStartRecord, data.type.record.RecordCount); #endif len = arf_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, &data); } else { error = true; error_class = ERROR_CLASS_OBJECT; error_code = ERROR_CODE_FILE_ACCESS_DENIED; } } else { error = true; error_class = ERROR_CLASS_SERVICES; error_code = ERROR_CODE_INVALID_FILE_ACCESS_METHOD; #if PRINT_ENABLED fprintf(stderr, "Record Access Requested. Sending Error!\n"); #endif } } else { error = true; error_class = ERROR_CLASS_SERVICES; error_code = ERROR_CODE_INCONSISTENT_OBJECT_TYPE; } if (error) { len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_ATOMIC_READ_FILE, error_class, error_code); } ARF_ABORT: pdu_len += len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) { fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno)); } #endif return; }