cb243c36a8
* Change MIT license texts to SPDX-License-Identifier SPDX-License-Identifier is much easier to understand and grep than license text so use that instead. * Change GPL exception license texts to SPDX-License-Identifier SPDX-License-Identifier is much easier to understand and grep than license text so use that instead. * Change misc license texts to SPDX-License-Identifier There are some external code in repo which are not licenses as most of the stuff in this repo. We still want every file to have SPDX identifier to easily grep licenses. * Add currently used license files Even though Bacnet-Stack is using SPDX identifiers we still need to give those license files with source. For this reason add all license files to license/ folder. SPDX has also files which would make same thing but this is style which example Linux kernel is using and it is quite clear so I choose that one for now. I choosed not yet bring CC-PDDC as that is not right license for those files. --------- Co-authored-by: Kari Argillander <kari.argillander@fidelix.com>
211 lines
8.2 KiB
C
211 lines
8.2 KiB
C
/**************************************************************************
|
|
*
|
|
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
*********************************************************************/
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
/* BACnet Stack defines - first */
|
|
#include "bacnet/bacdef.h"
|
|
/* BACnet Stack API */
|
|
#include "bacnet/bacdcode.h"
|
|
#include "bacnet/bacerror.h"
|
|
#include "bacnet/bacdevobjpropref.h"
|
|
#include "bacnet/apdu.h"
|
|
#include "bacnet/npdu.h"
|
|
#include "bacnet/abort.h"
|
|
#include "bacnet/reject.h"
|
|
#include "bacnet/rp.h"
|
|
/* basic objects, services, TSM, and datalink */
|
|
#include "bacnet/basic/object/device.h"
|
|
#if (BACNET_PROTOCOL_REVISION >= 17)
|
|
#include "bacnet/basic/object/netport.h"
|
|
#endif
|
|
#include "bacnet/basic/tsm/tsm.h"
|
|
#include "bacnet/basic/services.h"
|
|
#include "bacnet/datalink/datalink.h"
|
|
|
|
/** @file h_rp.c Handles Read Property requests. */
|
|
|
|
/** Handler for a ReadProperty Service request.
|
|
* @ingroup DSRP
|
|
* This handler will be invoked by apdu_handler() if it has been enabled
|
|
* by a call to apdu_set_confirmed_handler().
|
|
* This handler builds a response packet, which is
|
|
* - an Abort if
|
|
* - the message is segmented
|
|
* - if decoding fails
|
|
* - if the response would be too large
|
|
* - the result from Device_Read_Property(), if it succeeds
|
|
* - an Error if Device_Read_Property() fails
|
|
* or there isn't enough room in the APDU to fit the data.
|
|
*
|
|
* @param service_request [in] The contents of the service request.
|
|
* @param service_len [in] The length of the service_request.
|
|
* @param src [in] BACNET_ADDRESS of the source of the message
|
|
* @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information
|
|
* decoded from the APDU header of this message.
|
|
*/
|
|
void handler_read_property(uint8_t *service_request,
|
|
uint16_t service_len,
|
|
BACNET_ADDRESS *src,
|
|
BACNET_CONFIRMED_SERVICE_DATA *service_data)
|
|
{
|
|
BACNET_READ_PROPERTY_DATA rpdata;
|
|
int len = 0;
|
|
int pdu_len = 0;
|
|
int apdu_len = -1;
|
|
int npdu_len = -1;
|
|
BACNET_NPDU_DATA npdu_data;
|
|
bool error = true; /* assume that there is an error */
|
|
int bytes_sent = 0;
|
|
BACNET_ADDRESS my_address;
|
|
|
|
/* configure default error code as an abort since it is common */
|
|
rpdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
|
/* encode the NPDU portion of the packet */
|
|
datalink_get_my_address(&my_address);
|
|
npdu_encode_npdu_data(&npdu_data, false, service_data->priority);
|
|
npdu_len = npdu_encode_pdu(
|
|
&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data);
|
|
if (npdu_len <= 0) {
|
|
/* If 0 or negative, there were problems with the data or encoding. */
|
|
len = BACNET_STATUS_ABORT;
|
|
#if PRINT_ENABLED
|
|
fprintf(stderr, "RP: npdu_encode_pdu error. Sending Abort!\n");
|
|
#endif
|
|
} else if (service_data->segmented_message) {
|
|
/* we don't support segmentation - send an abort */
|
|
len = BACNET_STATUS_ABORT;
|
|
#if PRINT_ENABLED
|
|
fprintf(stderr, "RP: Segmented message. Sending Abort!\n");
|
|
#endif
|
|
} else {
|
|
len = rp_decode_service_request(service_request, service_len, &rpdata);
|
|
#if PRINT_ENABLED
|
|
if (len <= 0) {
|
|
fprintf(stderr, "RP: Unable to decode Request!\n");
|
|
}
|
|
#endif
|
|
if (len < 0) {
|
|
/* bad decoding - skip to error/reject/abort handling */
|
|
error = true;
|
|
#if PRINT_ENABLED
|
|
fprintf(stderr, "RP: Bad Encoding.\n");
|
|
#endif
|
|
} else {
|
|
/* When the object-type in the Object Identifier parameter
|
|
contains the value DEVICE and the instance in the 'Object
|
|
Identifier' parameter contains the value 4194303, the responding
|
|
BACnet-user shall treat the Object Identifier as if it correctly
|
|
matched the local Device object. This allows the device instance
|
|
of a device that does not generate I-Am messages to be
|
|
determined. */
|
|
if ((rpdata.object_type == OBJECT_DEVICE) &&
|
|
(rpdata.object_instance == BACNET_MAX_INSTANCE)) {
|
|
rpdata.object_instance = Device_Object_Instance_Number();
|
|
}
|
|
#if (BACNET_PROTOCOL_REVISION >= 17)
|
|
/* When the object-type in the Object Identifier parameter
|
|
contains the value NETWORK_PORT and the instance in the 'Object
|
|
Identifier' parameter contains the value 4194303, the responding
|
|
BACnet-user shall treat the Object Identifier as if it correctly
|
|
matched the local Network Port object representing the network
|
|
port through which the request was received. This allows the
|
|
network port instance of the network port that was used to
|
|
receive the request to be determined. */
|
|
if ((rpdata.object_type == OBJECT_NETWORK_PORT) &&
|
|
(rpdata.object_instance == BACNET_MAX_INSTANCE)) {
|
|
rpdata.object_instance = Network_Port_Index_To_Instance(0);
|
|
}
|
|
#endif
|
|
apdu_len =
|
|
rp_ack_encode_apdu_init(&Handler_Transmit_Buffer[npdu_len],
|
|
service_data->invoke_id, &rpdata);
|
|
/* configure our storage */
|
|
rpdata.application_data =
|
|
&Handler_Transmit_Buffer[npdu_len + apdu_len];
|
|
rpdata.application_data_len =
|
|
sizeof(Handler_Transmit_Buffer) - (npdu_len + apdu_len);
|
|
len = Device_Read_Property(&rpdata);
|
|
if (len >= 0) {
|
|
apdu_len += len;
|
|
len = rp_ack_encode_apdu_object_property_end(
|
|
&Handler_Transmit_Buffer[npdu_len + apdu_len]);
|
|
apdu_len += len;
|
|
if (apdu_len > service_data->max_resp) {
|
|
/* too big for the sender - send an abort!
|
|
Setting of error code needed here as read property
|
|
processing may have overridden the default set at start
|
|
*/
|
|
rpdata.error_code =
|
|
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
|
len = BACNET_STATUS_ABORT;
|
|
#if PRINT_ENABLED
|
|
fprintf(stderr, "RP: Message too large.\n");
|
|
#endif
|
|
} else {
|
|
#if PRINT_ENABLED
|
|
fprintf(stderr, "RP: Sending Ack!\n");
|
|
#endif
|
|
error = false;
|
|
}
|
|
} else {
|
|
#if PRINT_ENABLED
|
|
fprintf(stderr, "RP: Device_Read_Property: ");
|
|
if (len == BACNET_STATUS_ABORT) {
|
|
fprintf(stderr, "Abort!\n");
|
|
} else if (len == BACNET_STATUS_ERROR) {
|
|
fprintf(stderr, "Error!\n");
|
|
} else if (len == BACNET_STATUS_REJECT) {
|
|
fprintf(stderr, "Reject!\n");
|
|
} else {
|
|
fprintf(stderr, "Unknown Len=%d\n", len);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
if (error) {
|
|
if (len == BACNET_STATUS_ABORT) {
|
|
apdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[npdu_len],
|
|
service_data->invoke_id,
|
|
abort_convert_error_code(rpdata.error_code), true);
|
|
#if PRINT_ENABLED
|
|
fprintf(stderr, "RP: Sending Abort!\n");
|
|
#endif
|
|
} else if (len == BACNET_STATUS_ERROR) {
|
|
apdu_len = bacerror_encode_apdu(&Handler_Transmit_Buffer[npdu_len],
|
|
service_data->invoke_id, SERVICE_CONFIRMED_READ_PROPERTY,
|
|
rpdata.error_class, rpdata.error_code);
|
|
#if PRINT_ENABLED
|
|
fprintf(stderr, "RP: Sending Error!\n");
|
|
#endif
|
|
} else if (len == BACNET_STATUS_REJECT) {
|
|
apdu_len = reject_encode_apdu(&Handler_Transmit_Buffer[npdu_len],
|
|
service_data->invoke_id,
|
|
reject_convert_error_code(rpdata.error_code));
|
|
#if PRINT_ENABLED
|
|
fprintf(stderr, "RP: Sending Reject!\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
pdu_len = npdu_len + apdu_len;
|
|
bytes_sent = datalink_send_pdu(
|
|
src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
|
if (bytes_sent <= 0) {
|
|
#if PRINT_ENABLED
|
|
fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno));
|
|
#endif
|
|
}
|
|
|
|
return;
|
|
}
|