Revert "Added segmentation support for server reply. (#974)"
This reverts commit 3ea710f92f.
This commit is contained in:
@@ -16,11 +16,6 @@ The git repositories are hosted at the following sites:
|
||||
|
||||
### Security
|
||||
### Added
|
||||
|
||||
* Added segmentation support for server devices for some services.
|
||||
Configure BACNET_SEGMENTATION_ENABLED=1 to include in the library,
|
||||
and adjust BACNET_MAX_SEGMENTS_ACCEPTED for maximum number of segments. (#974)
|
||||
|
||||
### Changed
|
||||
|
||||
* Changed basic object API for units properties to use BACNET_ENGINEERING_UNITS
|
||||
|
||||
@@ -84,11 +84,6 @@ option(
|
||||
"compile with secure-connect support"
|
||||
OFF)
|
||||
|
||||
option(
|
||||
BACNET_SEGMENTATION_ENABLED
|
||||
"enable segmentation"
|
||||
ON)
|
||||
|
||||
if(NOT (BACDL_ETHERNET OR
|
||||
BACDL_MSTP OR
|
||||
BACDL_ARCNET OR
|
||||
@@ -677,8 +672,6 @@ add_library(${PROJECT_NAME}
|
||||
src/bacnet/rp.h
|
||||
src/bacnet/rpm.c
|
||||
src/bacnet/rpm.h
|
||||
$<$<BOOL:${BACNET_SEGMENTATION_ENABLED}>:src/bacnet/segmentack.c>
|
||||
$<$<BOOL:${BACNET_SEGMENTATION_ENABLED}>:src/bacnet/segmentack.h>
|
||||
src/bacnet/timer_value.c
|
||||
src/bacnet/timer_value.h
|
||||
src/bacnet/timestamp.c
|
||||
@@ -730,7 +723,6 @@ target_compile_definitions(
|
||||
$<$<BOOL:${BACDL_NONE}>:BACDL_NONE>
|
||||
$<$<BOOL:${BACNET_PROPERTY_LISTS}>:BACNET_PROPERTY_LISTS=1>
|
||||
$<$<BOOL:${BAC_ROUTING}>:BAC_ROUTING>
|
||||
$<$<BOOL:${BACNET_SEGMENTATION_ENABLED}>:BACNET_SEGMENTATION_ENABLED>
|
||||
$<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:BACNET_STACK_STATIC_DEFINE>
|
||||
PRIVATE
|
||||
PRINT_ENABLED=1)
|
||||
@@ -1283,4 +1275,3 @@ message(STATUS "BACNET: BACDL_ARCNET:...................\"${BACDL_ARCNET}\"")
|
||||
message(STATUS "BACNET: BACDL_MSTP:.....................\"${BACDL_MSTP}\"")
|
||||
message(STATUS "BACNET: BACDL_ZIGBEE:...................\"${BACDL_ZIGBEE}\"")
|
||||
message(STATUS "BACNET: BACDL_ETHERNET:.................\"${BACDL_ETHERNET}\"")
|
||||
message(STATUS "BACNET: BACNET_SEGMENTATION_ENABLED:....\"${BACNET_SEGMENTATION_ENABLED}\"")
|
||||
|
||||
@@ -224,10 +224,6 @@ server-discover:
|
||||
server-mini:
|
||||
$(MAKE) LEGACY=true NOTIFY=false -s -C apps $@
|
||||
|
||||
.PHONY: server-segmentation
|
||||
server-segmentation:
|
||||
$(MAKE) LEGACY=true SEGMENT=true -s -C apps server
|
||||
|
||||
.PHONY: sc-hub
|
||||
sc-hub:
|
||||
$(MAKE) LEGACY=true BACDL=bsc -s -C apps $@
|
||||
|
||||
@@ -223,11 +223,6 @@ ifeq (${LEGACY},true)
|
||||
BACNET_DEFINES += -DBACNET_STACK_DEPRECATED_DISABLE
|
||||
endif
|
||||
|
||||
ifeq (${SEGMENT},true)
|
||||
# enable segmentation support
|
||||
BACNET_DEFINES += -DBACNET_SEGMENTATION_ENABLED=1
|
||||
endif
|
||||
|
||||
ifeq (${NOTIFY},false)
|
||||
# disable intrinsic reporting
|
||||
else
|
||||
|
||||
@@ -174,20 +174,6 @@ static void Init_Service_Handlers(void)
|
||||
(unsigned)object_data.object_instance);
|
||||
}
|
||||
}
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
printf("Segmentation is enabled.\n");
|
||||
/* create extra object to stress the object list */
|
||||
for (i = 0; i < 500; i++) {
|
||||
object_data.object_instance = BACNET_MAX_INSTANCE;
|
||||
object_data.object_type = OBJECT_ANALOG_INPUT;
|
||||
if (Device_Create_Object(&object_data)) {
|
||||
printf(
|
||||
"Created object %s-%u\n",
|
||||
bactext_object_type_name(object_data.object_type),
|
||||
(unsigned)object_data.object_instance);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* we need to handle who-is to support dynamic device binding */
|
||||
apdu_set_unconfirmed_handler(
|
||||
SERVICE_UNCONFIRMED_WHO_IS, handler_who_is_who_am_i_unicast);
|
||||
|
||||
@@ -58,11 +58,6 @@ bool Device_Set_Object_Instance_Number(uint32_t object_id)
|
||||
return status;
|
||||
}
|
||||
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(void)
|
||||
{
|
||||
return SEGMENTATION_NONE;
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Instance_Number(uint32_t object_id)
|
||||
{
|
||||
/* BACnet allows for a wildcard instance number */
|
||||
|
||||
@@ -32,21 +32,6 @@ typedef struct _confirmed_service_ack_data {
|
||||
uint8_t proposed_window_number;
|
||||
} BACNET_CONFIRMED_SERVICE_ACK_DATA;
|
||||
|
||||
typedef struct BACnet_Apdu_Fixed_Header {
|
||||
/* pdu type Confirmed Request or Complex ACK */
|
||||
uint8_t pdu_type;
|
||||
union {
|
||||
/* Data for pdu type PDU_TYPE_CONFIRMED_SERVICE_REQUEST */
|
||||
struct _confirmed_service_data request_data;
|
||||
/* Data for pdu type PDU_TYPE_COMPLEX_ACK */
|
||||
struct _confirmed_service_ack_data ack_data;
|
||||
/* Common data for both types */
|
||||
struct _confirmed_service_ack_data common_data;
|
||||
} service_data;
|
||||
/* Service number */
|
||||
uint8_t service_choice;
|
||||
} BACNET_APDU_FIXED_HEADER;
|
||||
|
||||
uint8_t apdu_network_priority(void);
|
||||
void apdu_network_priority_set(uint8_t pri);
|
||||
|
||||
|
||||
@@ -212,24 +212,8 @@ typedef struct BACnet_Object_Id {
|
||||
uint32_t instance;
|
||||
} BACNET_OBJECT_ID;
|
||||
|
||||
#if !defined(BACNET_MAX_SEGMENTS_ACCEPTED)
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
/* note: BACNET_MAX_SEGMENTS_ACCEPTED can be 1..255.
|
||||
ASDU in this library is usually sized for 16-bit at 65535 max.
|
||||
Therefore, the default here is limited to avoid overflow warnings. */
|
||||
#define BACNET_MAX_SEGMENTS_ACCEPTED 32
|
||||
#else
|
||||
#define BACNET_MAX_SEGMENTS_ACCEPTED 1
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(MAX_APDU)
|
||||
#define MAX_APDU 1476
|
||||
#endif
|
||||
#define MAX_NPDU (1 + 1 + 2 + 1 + MAX_MAC_LEN + 2 + 1 + MAX_MAC_LEN + 1 + 1 + 2)
|
||||
#define MAX_PDU (MAX_APDU + MAX_NPDU)
|
||||
/* Application Service Data Unit (ASDU) that has not yet been segmented
|
||||
into a protocol data unit (PDU) by the lower layer. */
|
||||
#define MAX_ASDU ((MAX_APDU * BACNET_MAX_SEGMENTS_ACCEPTED) + MAX_NPDU)
|
||||
|
||||
#define BACNET_ID_VALUE(bacnet_object_instance, bacnet_object_type) \
|
||||
((((bacnet_object_type) & BACNET_MAX_OBJECT) << BACNET_INSTANCE_BITS) | \
|
||||
|
||||
@@ -45,10 +45,6 @@ static struct Address_Cache_Entry {
|
||||
uint8_t Flags;
|
||||
uint32_t device_id;
|
||||
unsigned max_apdu;
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
uint8_t segmentation;
|
||||
uint16_t maxsegments;
|
||||
#endif
|
||||
BACNET_ADDRESS address;
|
||||
uint32_t TimeToLive;
|
||||
} Address_Cache[MAX_ADDRESS_CACHE];
|
||||
@@ -350,16 +346,9 @@ void address_set_device_TTL(
|
||||
* @param device_id Device-Id
|
||||
* @param max_apdu Pointer to a variable, taking the maximum APDU size.
|
||||
* @param src Pointer to address structure for return.
|
||||
* @param segmentation Pointer to a variable, taking the BACNET_SEGMENTATION
|
||||
* flag.
|
||||
* @param maxsegments Pointer to a variable, taking the maximum segments.
|
||||
*/
|
||||
bool address_segment_get_by_device(
|
||||
uint32_t device_id,
|
||||
unsigned *max_apdu,
|
||||
BACNET_ADDRESS *src,
|
||||
uint8_t *segmentation,
|
||||
uint16_t *maxsegments)
|
||||
bool address_get_by_device(
|
||||
uint32_t device_id, unsigned *max_apdu, BACNET_ADDRESS *src)
|
||||
{
|
||||
struct Address_Cache_Entry *pMatch;
|
||||
bool found = false; /* return value */
|
||||
@@ -375,20 +364,6 @@ bool address_segment_get_by_device(
|
||||
if (max_apdu) {
|
||||
*max_apdu = pMatch->max_apdu;
|
||||
}
|
||||
if (segmentation) {
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
*segmentation = pMatch->segmentation;
|
||||
#else
|
||||
*segmentation = SEGMENTATION_NONE;
|
||||
#endif
|
||||
}
|
||||
if (maxsegments) {
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
*maxsegments = pMatch->maxsegments;
|
||||
#else
|
||||
*maxsegments = 1;
|
||||
#endif
|
||||
}
|
||||
/* Prove we found it */
|
||||
found = true;
|
||||
}
|
||||
@@ -400,19 +375,6 @@ bool address_segment_get_by_device(
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the cached addresBACNET_STACK_EXPORT
|
||||
s for the given device-id
|
||||
* @param device_id Device-Id
|
||||
* @param max_apdu Pointer to a variable, taking the maximum APDU size.
|
||||
* @param src Pointer to address structure for return.
|
||||
*/
|
||||
bool address_get_by_device(
|
||||
uint32_t device_id, unsigned *max_apdu, BACNET_ADDRESS *src)
|
||||
{
|
||||
return address_segment_get_by_device(device_id, max_apdu, src, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a device id from a given MAC address.
|
||||
*
|
||||
|
||||
@@ -43,14 +43,6 @@ BACNET_STACK_EXPORT
|
||||
bool address_get_by_device(
|
||||
uint32_t device_id, unsigned *max_apdu, BACNET_ADDRESS *src);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool address_segment_get_by_device(
|
||||
uint32_t device_id,
|
||||
unsigned *max_apdu,
|
||||
BACNET_ADDRESS *src,
|
||||
uint8_t *segmentation,
|
||||
uint16_t *maxsegments);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool address_get_by_index(
|
||||
unsigned index,
|
||||
|
||||
@@ -1145,11 +1145,7 @@ uint8_t Device_Protocol_Revision(void)
|
||||
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(void)
|
||||
{
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
return SEGMENTATION_BOTH;
|
||||
#else
|
||||
return SEGMENTATION_NONE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1620,12 +1616,8 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
rpdata->object_instance, rpdata->array_index,
|
||||
Device_Object_List_Element_Encode, count, apdu, apdu_max);
|
||||
if (apdu_len == BACNET_STATUS_ABORT) {
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
rpdata->error_code = ERROR_CODE_ABORT_BUFFER_OVERFLOW;
|
||||
#else
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
#endif
|
||||
} else if (apdu_len == BACNET_STATUS_ERROR) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
|
||||
@@ -26,10 +26,6 @@ static uint16_t Timeout_Milliseconds = 3000;
|
||||
/* Number of APDU Retries */
|
||||
static uint8_t Number_Of_Retries = 3;
|
||||
static uint8_t Local_Network_Priority; /* Fixing test 10.1.2 Network priority */
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
/* APDU Segment Timeout in Milliseconds */
|
||||
static uint16_t Segment_Timeout_Milliseconds = 5000;
|
||||
#endif
|
||||
|
||||
/* a simple table for crossing the services supported */
|
||||
static BACNET_SERVICES_SUPPORTED
|
||||
@@ -556,109 +552,6 @@ static bool apdu_unconfirmed_dcc_disabled(uint8_t service_choice)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Invoke special handler for confirmed service */
|
||||
static void invoke_confirmed_service_service_request(
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *service_data,
|
||||
uint8_t service_choice,
|
||||
uint8_t *service_request,
|
||||
uint32_t service_request_len)
|
||||
{
|
||||
if (apdu_confirmed_dcc_disabled(service_choice)) {
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice
|
||||
APDUs shall be processed and no messages shall be
|
||||
initiated. */
|
||||
return;
|
||||
}
|
||||
if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) &&
|
||||
(Confirmed_Function[service_choice])) {
|
||||
Confirmed_Function[service_choice](
|
||||
service_request, service_request_len, src, service_data);
|
||||
} else if (Unrecognized_Service_Handler) {
|
||||
Unrecognized_Service_Handler(
|
||||
service_request, service_request_len, src, service_data);
|
||||
}
|
||||
}
|
||||
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
/** Handler for messages with segmentation :
|
||||
- store new packet if sequence number is ok
|
||||
- NACK packet if sequence number is not ok
|
||||
- call the final functions with reassembled data when last packet ok is
|
||||
received
|
||||
*/
|
||||
static void apdu_handler_confirmed_service_segment(
|
||||
BACNET_ADDRESS *src,
|
||||
uint8_t *apdu, /* APDU data */
|
||||
uint32_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t internal_service_id = 0;
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint32_t len = 0; /* counts where we are in PDU */
|
||||
bool segment_ok;
|
||||
|
||||
len = apdu_decode_confirmed_service_request(
|
||||
&apdu[0], /* APDU data */
|
||||
apdu_len, &service_data, &service_choice, &service_request,
|
||||
&service_request_len);
|
||||
if (len == 0) {
|
||||
/* service data unable to be decoded - simply drop */
|
||||
return;
|
||||
}
|
||||
/* new segment : memorize it */
|
||||
segment_ok = tsm_set_segmented_confirmed_service_received(
|
||||
src, &service_data, &internal_service_id, &service_request,
|
||||
&service_request_len);
|
||||
/* last segment */
|
||||
if (segment_ok && !service_data.more_follows) {
|
||||
/* Clear peer information */
|
||||
tsm_clear_peer_id(internal_service_id);
|
||||
/* Invoke service handler */
|
||||
invoke_confirmed_service_service_request(
|
||||
src, &service_data, service_choice, service_request,
|
||||
service_request_len);
|
||||
/* We must free invoke_id, and associated data */
|
||||
tsm_free_invoke_id_check(internal_service_id, NULL, true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Handler for normal message without segmentation, or segmented complete
|
||||
* message reassembled all-in-one */
|
||||
static void apdu_handler_confirmed_service(
|
||||
BACNET_ADDRESS *src,
|
||||
uint8_t *apdu, /* APDU data */
|
||||
uint32_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint32_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
len = apdu_decode_confirmed_service_request(
|
||||
&apdu[0], /* APDU data */
|
||||
apdu_len, &service_data, &service_choice, &service_request,
|
||||
&service_request_len);
|
||||
if (len == 0) {
|
||||
/* service data unable to be decoded - simply drop */
|
||||
return;
|
||||
}
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
/* Check for unexpected request is received in active TSM state */
|
||||
if (tsm_is_invalid_apdu_in_this_state(src, &service_data)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
invoke_confirmed_service_service_request(
|
||||
src, &service_data, service_choice, service_request,
|
||||
service_request_len);
|
||||
}
|
||||
|
||||
/** Process the APDU header and invoke the appropriate service handler
|
||||
* to manage the received request.
|
||||
* Almost all requests and ACKs invoke this function.
|
||||
@@ -674,15 +567,11 @@ void apdu_handler(
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_PDU_TYPE pdu_type;
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
int len = 0; /* counts where we are in PDU */
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
uint8_t sequence_number = 0;
|
||||
uint8_t actual_window_size = 0;
|
||||
bool nak = false;
|
||||
#endif
|
||||
#if !BACNET_SVC_SERVER
|
||||
uint8_t invoke_id = 0;
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA service_ack_data = { 0 };
|
||||
@@ -701,14 +590,27 @@ void apdu_handler(
|
||||
pdu_type = apdu[0] & 0xF0;
|
||||
switch (pdu_type) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
/* segmented_message_reception ? */
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
if (apdu[0] & BIT(3)) {
|
||||
apdu_handler_confirmed_service_segment(src, apdu, apdu_len);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
apdu_handler_confirmed_service(src, apdu, apdu_len);
|
||||
len = apdu_decode_confirmed_service_request(
|
||||
apdu, apdu_len, &service_data, &service_choice,
|
||||
&service_request, &service_request_len);
|
||||
if (len == 0) {
|
||||
/* service data unable to be decoded - simply drop */
|
||||
break;
|
||||
}
|
||||
if (apdu_confirmed_dcc_disabled(service_choice)) {
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice
|
||||
APDUs shall be processed and no messages shall be
|
||||
initiated. */
|
||||
break;
|
||||
}
|
||||
if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) &&
|
||||
(Confirmed_Function[service_choice])) {
|
||||
Confirmed_Function[service_choice](
|
||||
service_request, service_request_len, src, &service_data);
|
||||
} else if (Unrecognized_Service_Handler) {
|
||||
Unrecognized_Service_Handler(
|
||||
service_request, service_request_len, src, &service_data);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
@@ -783,24 +685,9 @@ void apdu_handler(
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
#if !BACNET_SEGMENTATION_ENABLED
|
||||
/* FIXME: what about a denial of service attack here?
|
||||
we could check src to see if that matched the tsm */
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
#else
|
||||
if (apdu_len < 4) {
|
||||
break;
|
||||
}
|
||||
server = apdu[0] & 0x01;
|
||||
nak = apdu[0] & 0x02;
|
||||
invoke_id = apdu[1];
|
||||
sequence_number = apdu[2];
|
||||
actual_window_size = apdu[3];
|
||||
/* we care because we support segmented message sending */
|
||||
tsm_segmentack_received(
|
||||
invoke_id, sequence_number, actual_window_size, nak, server,
|
||||
src);
|
||||
#endif
|
||||
break;
|
||||
case PDU_TYPE_ERROR:
|
||||
if (apdu_len < 3) {
|
||||
@@ -827,12 +714,7 @@ void apdu_handler(
|
||||
(BACNET_ERROR_CODE)error_code);
|
||||
}
|
||||
}
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
/*Release the data*/
|
||||
tsm_free_invoke_id_segmentation(src, invoke_id);
|
||||
#else
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
#endif
|
||||
break;
|
||||
case PDU_TYPE_REJECT:
|
||||
if (apdu_len < 3) {
|
||||
@@ -843,12 +725,7 @@ void apdu_handler(
|
||||
if (Reject_Function) {
|
||||
Reject_Function(src, invoke_id, reason);
|
||||
}
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
/*Release the data*/
|
||||
tsm_free_invoke_id_segmentation(src, invoke_id);
|
||||
#else
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
#endif
|
||||
break;
|
||||
case PDU_TYPE_ABORT:
|
||||
if (apdu_len < 3) {
|
||||
@@ -857,156 +734,13 @@ void apdu_handler(
|
||||
server = apdu[0] & 0x01;
|
||||
invoke_id = apdu[1];
|
||||
reason = apdu[2];
|
||||
if (!server) {
|
||||
/*AbortPDU_Received*/
|
||||
if (Abort_Function) {
|
||||
Abort_Function(src, invoke_id, reason, server);
|
||||
}
|
||||
if (Abort_Function) {
|
||||
Abort_Function(src, invoke_id, reason, server);
|
||||
}
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
else {
|
||||
/*SendAbort*/
|
||||
tsm_abort_pdu_send(invoke_id, src, reason, server);
|
||||
}
|
||||
/*Release the data*/
|
||||
tsm_free_invoke_id_segmentation(src, invoke_id);
|
||||
#else
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
/*Return the APDU segment timeout*/
|
||||
uint16_t apdu_segment_timeout(void)
|
||||
{
|
||||
return Segment_Timeout_Milliseconds;
|
||||
}
|
||||
|
||||
/*Set the APDU segment timeout*/
|
||||
void apdu_segment_timeout_set(uint16_t milliseconds)
|
||||
{
|
||||
Segment_Timeout_Milliseconds = milliseconds;
|
||||
}
|
||||
|
||||
/** Process the APDU header and invoke the appropriate service handler
|
||||
* to manage the received request.
|
||||
* Almost all requests and ACKs invoke this function.
|
||||
* @ingroup MISCHNDLR
|
||||
*
|
||||
* @param apdu [in] The apdu portion of the response, to be sent
|
||||
* @param fixed_pdu_header [in] The apdu header for the response
|
||||
* @return apdu_length[out] The length of the apdu header
|
||||
*/
|
||||
int apdu_encode_fixed_header(
|
||||
uint8_t *apdu, BACNET_APDU_FIXED_HEADER *fixed_pdu_header)
|
||||
{
|
||||
int apdu_len = 0;
|
||||
switch (fixed_pdu_header->pdu_type) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
apdu[apdu_len++] = fixed_pdu_header->pdu_type
|
||||
/* flag 'SA' if we accept many segments */
|
||||
| (fixed_pdu_header->service_data.request_data
|
||||
.segmented_response_accepted
|
||||
? 0x02
|
||||
: 0x00)
|
||||
/* flag 'MOR' if we more segments are coming */
|
||||
| (fixed_pdu_header->service_data.request_data.more_follows
|
||||
? 0x04
|
||||
: 0x00)
|
||||
/* flag 'SEG' if we more segments are coming */
|
||||
| (fixed_pdu_header->service_data.request_data.segmented_message
|
||||
? 0x08
|
||||
: 0x00);
|
||||
apdu[apdu_len++] = encode_max_segs_max_apdu(
|
||||
fixed_pdu_header->service_data.request_data.max_segs,
|
||||
fixed_pdu_header->service_data.request_data.max_resp);
|
||||
apdu[apdu_len++] =
|
||||
fixed_pdu_header->service_data.request_data.invoke_id;
|
||||
/* extra data for segmented messages sending */
|
||||
if (fixed_pdu_header->service_data.request_data.segmented_message) {
|
||||
/* packet sequence number */
|
||||
apdu[apdu_len++] =
|
||||
fixed_pdu_header->service_data.request_data.sequence_number;
|
||||
/* window size proposal */
|
||||
apdu[apdu_len++] = fixed_pdu_header->service_data.request_data
|
||||
.proposed_window_number;
|
||||
}
|
||||
/* service choice */
|
||||
apdu[apdu_len++] = fixed_pdu_header->service_choice;
|
||||
break;
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
apdu[apdu_len++] = fixed_pdu_header->pdu_type
|
||||
/* flag 'MOR' if we more segments are coming */
|
||||
| (fixed_pdu_header->service_data.ack_data.more_follows ? 0x04
|
||||
: 0x00)
|
||||
/* flag 'SEG' if we more segments are coming */
|
||||
| (fixed_pdu_header->service_data.ack_data.segmented_message
|
||||
? 0x08
|
||||
: 0x00);
|
||||
apdu[apdu_len++] =
|
||||
fixed_pdu_header->service_data.ack_data.invoke_id;
|
||||
/* extra data for segmented messages sending */
|
||||
if (fixed_pdu_header->service_data.ack_data.segmented_message) {
|
||||
/* packet sequence number */
|
||||
apdu[apdu_len++] =
|
||||
fixed_pdu_header->service_data.ack_data.sequence_number;
|
||||
/* window size proposal */
|
||||
apdu[apdu_len++] = fixed_pdu_header->service_data.ack_data
|
||||
.proposed_window_number;
|
||||
}
|
||||
/* service choice */
|
||||
apdu[apdu_len++] = fixed_pdu_header->service_choice;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/** Handler to assign the header fields to the response
|
||||
* The response can be segmented/unsegmented
|
||||
*
|
||||
* @param fixed_pdu_header [in] The apdu header of the response, to be sent.
|
||||
* @param pdu_type [in] The pdu_type of the response.
|
||||
* @param invoke_id [in] The invoike_id of the response
|
||||
* @param service[in] The service choice for which the response has to be
|
||||
* processed
|
||||
* @param max_apdu[in] The maximum apdu length
|
||||
*/
|
||||
void apdu_init_fixed_header(
|
||||
BACNET_APDU_FIXED_HEADER *fixed_pdu_header,
|
||||
uint8_t pdu_type,
|
||||
uint8_t invoke_id,
|
||||
uint8_t service,
|
||||
int max_apdu)
|
||||
{
|
||||
fixed_pdu_header->pdu_type = pdu_type;
|
||||
|
||||
fixed_pdu_header->service_data.common_data.invoke_id = invoke_id;
|
||||
fixed_pdu_header->service_data.common_data.more_follows = false;
|
||||
fixed_pdu_header->service_data.common_data.proposed_window_number = 0;
|
||||
fixed_pdu_header->service_data.common_data.sequence_number = 0;
|
||||
fixed_pdu_header->service_data.common_data.segmented_message = false;
|
||||
switch (pdu_type) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
fixed_pdu_header->service_data.request_data.max_segs =
|
||||
BACNET_MAX_SEGMENTS_ACCEPTED;
|
||||
/* allow to specify a lower APDU size : support arbitrary reduction
|
||||
* of APDU packets between peers */
|
||||
fixed_pdu_header->service_data.request_data.max_resp =
|
||||
max_apdu < MAX_APDU ? max_apdu : MAX_APDU;
|
||||
fixed_pdu_header->service_data.request_data
|
||||
.segmented_response_accepted = BACNET_MAX_SEGMENTS_ACCEPTED > 1;
|
||||
break;
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fixed_pdu_header->service_choice = service;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -162,24 +162,6 @@ void apdu_handler(
|
||||
uint8_t *apdu, /* APDU data */
|
||||
uint16_t pdu_len); /* for confirmed messages */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t apdu_segment_timeout(void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void apdu_segment_timeout_set(uint16_t milliseconds);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int apdu_encode_fixed_header(
|
||||
uint8_t *apdu, BACNET_APDU_FIXED_HEADER *fixed_pdu_header);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void apdu_init_fixed_header(
|
||||
BACNET_APDU_FIXED_HEADER *fixed_pdu_header,
|
||||
uint8_t pdu_type,
|
||||
uint8_t invoke_id,
|
||||
uint8_t service,
|
||||
int max_apdu);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -108,9 +108,7 @@ void handler_device_communication_control(
|
||||
debug_print("DeviceCommunicationControl: "
|
||||
"Missing Required Parameter. Sending Reject!\n");
|
||||
goto DCC_FAILURE;
|
||||
}
|
||||
#if !BACNET_SEGMENTATION_ENABLED
|
||||
else if (service_data->segmented_message) {
|
||||
} else if (service_data->segmented_message) {
|
||||
len = abort_encode_apdu(
|
||||
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
@@ -118,7 +116,6 @@ void handler_device_communication_control(
|
||||
"Sending Abort - segmented message.\n");
|
||||
goto DCC_FAILURE;
|
||||
}
|
||||
#endif
|
||||
/* decode the service request only */
|
||||
len = dcc_decode_service_request(
|
||||
service_request, service_len, &timeDuration, &state, &password);
|
||||
|
||||
@@ -71,16 +71,13 @@ void handler_reinitialize_device(
|
||||
debug_print("ReinitializeDevice: Missing Required Parameter. "
|
||||
"Sending Reject!\n");
|
||||
goto RD_ABORT;
|
||||
}
|
||||
#if !BACNET_SEGMENTATION_ENABLED
|
||||
else if (service_data->segmented_message) {
|
||||
} else if (service_data->segmented_message) {
|
||||
len = abort_encode_apdu(
|
||||
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
debug_print("ReinitializeDevice: Sending Abort - segmented message.\n");
|
||||
goto RD_ABORT;
|
||||
}
|
||||
#endif
|
||||
/* decode the service request only */
|
||||
len = rd_decode_service_request(
|
||||
service_request, service_len, &rd_data.state, &rd_data.password);
|
||||
|
||||
@@ -30,12 +30,6 @@
|
||||
#include "bacnet/basic/sys/debug.h"
|
||||
#include "bacnet/datalink/datalink.h"
|
||||
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
#define BACNET_RP_BUFFER_OVERFLOW ERROR_CODE_ABORT_BUFFER_OVERFLOW
|
||||
#else
|
||||
#define BACNET_RP_BUFFER_OVERFLOW ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED
|
||||
#endif
|
||||
|
||||
/** @file h_rp.c Handles Read Property requests. */
|
||||
|
||||
/** Handler for a ReadProperty Service request.
|
||||
@@ -44,7 +38,7 @@
|
||||
* by a call to apdu_set_confirmed_handler().
|
||||
* This handler builds a response packet, which is
|
||||
* - an Abort if
|
||||
* - the message is segmented and segmentation is not supported
|
||||
* - the message is segmented
|
||||
* - if decoding fails
|
||||
* - if the response would be too large
|
||||
* - the result from Device_Read_Property(), if it succeeds
|
||||
@@ -65,7 +59,6 @@ void handler_read_property(
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
int len = 0;
|
||||
int max_resp = 0;
|
||||
int pdu_len = 0;
|
||||
int apdu_len = -1;
|
||||
int npdu_len = -1;
|
||||
@@ -73,13 +66,9 @@ void handler_read_property(
|
||||
bool error = true; /* assume that there is an error */
|
||||
int bytes_sent = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
BACNET_APDU_FIXED_HEADER apdu_fixed_header;
|
||||
int apdu_header_len = 3;
|
||||
#endif
|
||||
|
||||
/* configure default error code as an abort since it is common */
|
||||
rpdata.error_code = BACNET_RP_BUFFER_OVERFLOW;
|
||||
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);
|
||||
@@ -93,12 +82,10 @@ void handler_read_property(
|
||||
len = BACNET_STATUS_REJECT;
|
||||
rpdata.error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
debug_print("RP: Missing Required Parameter. Sending Reject!\n");
|
||||
#if !BACNET_SEGMENTATION_ENABLED
|
||||
} else if (service_data->segmented_message) {
|
||||
/* we don't support segmentation - send an abort */
|
||||
len = BACNET_STATUS_ABORT;
|
||||
debug_print("RP: Segmented message. Sending Abort!\n");
|
||||
#endif
|
||||
} else {
|
||||
len = rp_decode_service_request(service_request, service_len, &rpdata);
|
||||
if (len <= 0) {
|
||||
@@ -129,13 +116,6 @@ void handler_read_property(
|
||||
rpdata.object_instance = Network_Port_Index_To_Instance(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
apdu_init_fixed_header(
|
||||
&apdu_fixed_header, PDU_TYPE_COMPLEX_ACK,
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_READ_PROPERTY,
|
||||
service_data->max_resp);
|
||||
#endif
|
||||
apdu_len = rp_ack_encode_apdu_init(
|
||||
&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id,
|
||||
&rpdata);
|
||||
@@ -154,25 +134,7 @@ void handler_read_property(
|
||||
len = rp_ack_encode_apdu_object_property_end(
|
||||
&Handler_Transmit_Buffer[npdu_len + apdu_len]);
|
||||
apdu_len += len;
|
||||
/* pick the smaller response packet: ours or theirs */
|
||||
max_resp = min(service_data->max_resp, MAX_APDU);
|
||||
if (apdu_len > max_resp) {
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
if (service_data->segmented_response_accepted) {
|
||||
npdu_encode_npdu_data(
|
||||
&npdu_data, true, MESSAGE_PRIORITY_NORMAL);
|
||||
npdu_len = npdu_encode_pdu(
|
||||
&Handler_Transmit_Buffer[0], src, &my_address,
|
||||
&npdu_data);
|
||||
|
||||
tsm_set_complexack_transaction(
|
||||
src, &npdu_data, &apdu_fixed_header, service_data,
|
||||
&Handler_Transmit_Buffer
|
||||
[npdu_len + apdu_header_len],
|
||||
(apdu_len - apdu_header_len));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
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
|
||||
@@ -181,7 +143,6 @@ void handler_read_property(
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
len = BACNET_STATUS_ABORT;
|
||||
debug_print("RP: Message too large.\n");
|
||||
#endif
|
||||
} else {
|
||||
debug_print("RP: Sending Ack!\n");
|
||||
error = false;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
@@ -34,17 +33,7 @@
|
||||
#include "bacnet/basic/sys/debug.h"
|
||||
#include "bacnet/datalink/datalink.h"
|
||||
|
||||
/* Smaller single threaded implementations prefer a
|
||||
single buffer for encoding each property from the RPM request. */
|
||||
#ifndef BACNET_RPM_PROPERTY_BUFFER_USE_CSTACK
|
||||
static uint8_t RPM_Prop_Buffer[MAX_ASDU - MAX_NPDU] = { 0 };
|
||||
#endif
|
||||
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
#define BACNET_RPM_BUFFER_OVERFLOW ERROR_CODE_ABORT_BUFFER_OVERFLOW
|
||||
#else
|
||||
#define BACNET_RPM_BUFFER_OVERFLOW ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED
|
||||
#endif
|
||||
static uint8_t Temp_Buf[MAX_APDU] = { 0 };
|
||||
|
||||
/**
|
||||
* @brief Fetches the lists of properties (array of BACNET_PROPERTY_ID's) for
|
||||
@@ -135,15 +124,12 @@ static int RPM_Encode_Property(
|
||||
size_t copy_len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
#ifdef BACNET_RPM_PROPERTY_BUFFER_USE_CSTACK
|
||||
uint8_t RPM_Prop_Buffer[MAX_ASDU - MAX_NPDU] = { 0 };
|
||||
#endif
|
||||
|
||||
len = rpm_ack_encode_apdu_object_property(
|
||||
&RPM_Prop_Buffer[0], rpmdata->object_property, rpmdata->array_index);
|
||||
copy_len = memcopy(&apdu[0], &RPM_Prop_Buffer[0], offset, len, max_apdu);
|
||||
&Temp_Buf[0], rpmdata->object_property, rpmdata->array_index);
|
||||
copy_len = memcopy(&apdu[0], &Temp_Buf[0], offset, len, max_apdu);
|
||||
if (copy_len == 0) {
|
||||
rpmdata->error_code = BACNET_RPM_BUFFER_OVERFLOW;
|
||||
rpmdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
return BACNET_STATUS_ABORT;
|
||||
}
|
||||
apdu_len += len;
|
||||
@@ -153,8 +139,8 @@ static int RPM_Encode_Property(
|
||||
rpdata.object_instance = rpmdata->object_instance;
|
||||
rpdata.object_property = rpmdata->object_property;
|
||||
rpdata.array_index = rpmdata->array_index;
|
||||
rpdata.application_data = &RPM_Prop_Buffer[0];
|
||||
rpdata.application_data_len = sizeof(RPM_Prop_Buffer);
|
||||
rpdata.application_data = &Temp_Buf[0];
|
||||
rpdata.application_data_len = sizeof(Temp_Buf);
|
||||
|
||||
if ((rpmdata->object_property == PROP_ALL) ||
|
||||
(rpmdata->object_property == PROP_REQUIRED) ||
|
||||
@@ -175,21 +161,21 @@ static int RPM_Encode_Property(
|
||||
}
|
||||
/* error was returned - encode that for the response */
|
||||
len = rpm_ack_encode_apdu_object_property_error(
|
||||
&RPM_Prop_Buffer[0], rpdata.error_class, rpdata.error_code);
|
||||
copy_len = memcopy(
|
||||
&apdu[0], &RPM_Prop_Buffer[0], offset + apdu_len, len, max_apdu);
|
||||
&Temp_Buf[0], rpdata.error_class, rpdata.error_code);
|
||||
copy_len =
|
||||
memcopy(&apdu[0], &Temp_Buf[0], offset + apdu_len, len, max_apdu);
|
||||
|
||||
if (copy_len == 0) {
|
||||
rpmdata->error_code = BACNET_RPM_BUFFER_OVERFLOW;
|
||||
rpmdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
return BACNET_STATUS_ABORT;
|
||||
}
|
||||
} else if ((offset + apdu_len + 1 + len + 1) < max_apdu) {
|
||||
/* enough room to fit the property value and tags */
|
||||
len = rpm_ack_encode_apdu_object_property_value(
|
||||
&apdu[offset + apdu_len], &RPM_Prop_Buffer[0], len);
|
||||
&apdu[offset + apdu_len], &Temp_Buf[0], len);
|
||||
} else {
|
||||
/* not enough room - abort! */
|
||||
rpmdata->error_code = BACNET_RPM_BUFFER_OVERFLOW;
|
||||
rpmdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
return BACNET_STATUS_ABORT;
|
||||
}
|
||||
apdu_len += len;
|
||||
@@ -203,7 +189,7 @@ static int RPM_Encode_Property(
|
||||
* by a call to apdu_set_confirmed_handler().
|
||||
* This handler builds a response packet, which is
|
||||
* - an Abort if
|
||||
* - the message is segmented and SEGMENTATION_NONE
|
||||
* - the message is segmented
|
||||
* - if decoding fails
|
||||
* - if the response would be too large
|
||||
* - the result from each included read request, if it succeeds
|
||||
@@ -234,14 +220,6 @@ void handler_read_property_multiple(
|
||||
int apdu_len = 0;
|
||||
int npdu_len = 0;
|
||||
int error = 0;
|
||||
int max_resp = 0;
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
BACNET_APDU_FIXED_HEADER apdu_fixed_header;
|
||||
int apdu_header_len = 3;
|
||||
#endif
|
||||
#ifdef BACNET_RPM_PROPERTY_BUFFER_USE_CSTACK
|
||||
uint8_t RPM_Prop_Buffer[MAX_ASDU - MAX_NPDU] = { 0 };
|
||||
#endif
|
||||
|
||||
if (service_data) {
|
||||
datalink_get_my_address(&my_address);
|
||||
@@ -252,12 +230,10 @@ void handler_read_property_multiple(
|
||||
rpmdata.error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
error = BACNET_STATUS_REJECT;
|
||||
debug_print("RPM: Missing Required Parameter. Sending Reject!\n");
|
||||
#if !BACNET_SEGMENTATION_ENABLED
|
||||
} else if (service_data->segmented_message) {
|
||||
rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
error = BACNET_STATUS_ABORT;
|
||||
debug_print("RPM: Segmented message. Sending Abort!\r\n");
|
||||
#endif
|
||||
} else {
|
||||
/* decode apdu request & encode apdu reply
|
||||
encode complex ack, invoke id, service choice */
|
||||
@@ -303,14 +279,14 @@ void handler_read_property_multiple(
|
||||
}
|
||||
#endif
|
||||
/* Stick this object id into the reply - if it will fit */
|
||||
len = rpm_ack_encode_apdu_object_begin(
|
||||
&RPM_Prop_Buffer[0], &rpmdata);
|
||||
len = rpm_ack_encode_apdu_object_begin(&Temp_Buf[0], &rpmdata);
|
||||
copy_len = memcopy(
|
||||
&Handler_Transmit_Buffer[npdu_len], &RPM_Prop_Buffer[0],
|
||||
apdu_len, len, sizeof(RPM_Prop_Buffer));
|
||||
&Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], apdu_len,
|
||||
len, MAX_APDU);
|
||||
if (copy_len == 0) {
|
||||
debug_print("RPM: Response too big!\n");
|
||||
rpmdata.error_code = BACNET_RPM_BUFFER_OVERFLOW;
|
||||
rpmdata.error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
error = BACNET_STATUS_ABORT;
|
||||
berror = true;
|
||||
break;
|
||||
@@ -345,9 +321,7 @@ void handler_read_property_multiple(
|
||||
rpmdata.object_type, rpmdata.object_instance)) {
|
||||
len = RPM_Encode_Property(
|
||||
&Handler_Transmit_Buffer[npdu_len],
|
||||
(uint16_t)apdu_len,
|
||||
sizeof(Handler_Transmit_Buffer) - npdu_len,
|
||||
&rpmdata);
|
||||
(uint16_t)apdu_len, MAX_APDU, &rpmdata);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
@@ -362,18 +336,18 @@ void handler_read_property_multiple(
|
||||
/* No array index options for this special property.
|
||||
Encode error for this object property response */
|
||||
len = rpm_ack_encode_apdu_object_property(
|
||||
&RPM_Prop_Buffer[0], rpmdata.object_property,
|
||||
&Temp_Buf[0], rpmdata.object_property,
|
||||
rpmdata.array_index);
|
||||
|
||||
copy_len = memcopy(
|
||||
&Handler_Transmit_Buffer[npdu_len],
|
||||
&RPM_Prop_Buffer[0], apdu_len, len,
|
||||
sizeof(RPM_Prop_Buffer));
|
||||
&Temp_Buf[0], apdu_len, len, MAX_APDU);
|
||||
|
||||
if (copy_len == 0) {
|
||||
debug_print(
|
||||
"RPM: Too full to encode property!\n");
|
||||
rpmdata.error_code = BACNET_RPM_BUFFER_OVERFLOW;
|
||||
rpmdata.error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
error = BACNET_STATUS_ABORT;
|
||||
/* The berror flag ensures that
|
||||
both loops will be broken! */
|
||||
@@ -383,17 +357,17 @@ void handler_read_property_multiple(
|
||||
|
||||
apdu_len += len;
|
||||
len = rpm_ack_encode_apdu_object_property_error(
|
||||
&RPM_Prop_Buffer[0], ERROR_CLASS_PROPERTY,
|
||||
&Temp_Buf[0], ERROR_CLASS_PROPERTY,
|
||||
ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY);
|
||||
|
||||
copy_len = memcopy(
|
||||
&Handler_Transmit_Buffer[npdu_len],
|
||||
&RPM_Prop_Buffer[0], apdu_len, len,
|
||||
sizeof(RPM_Prop_Buffer));
|
||||
&Temp_Buf[0], apdu_len, len, MAX_APDU);
|
||||
|
||||
if (copy_len == 0) {
|
||||
debug_print("RPM: Too full to encode error!\n");
|
||||
rpmdata.error_code = BACNET_RPM_BUFFER_OVERFLOW;
|
||||
rpmdata.error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
error = BACNET_STATUS_ABORT;
|
||||
/* The berror flag ensures that
|
||||
both loops will be broken! */
|
||||
@@ -422,10 +396,7 @@ void handler_read_property_multiple(
|
||||
rpmdata.object_instance)) {
|
||||
len = RPM_Encode_Property(
|
||||
&Handler_Transmit_Buffer[npdu_len],
|
||||
(uint16_t)apdu_len,
|
||||
sizeof(Handler_Transmit_Buffer) -
|
||||
npdu_len,
|
||||
&rpmdata);
|
||||
(uint16_t)apdu_len, MAX_APDU, &rpmdata);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
@@ -447,10 +418,7 @@ void handler_read_property_multiple(
|
||||
special_object_property, index);
|
||||
len = RPM_Encode_Property(
|
||||
&Handler_Transmit_Buffer[npdu_len],
|
||||
(uint16_t)apdu_len,
|
||||
sizeof(Handler_Transmit_Buffer) -
|
||||
npdu_len,
|
||||
&rpmdata);
|
||||
(uint16_t)apdu_len, MAX_APDU, &rpmdata);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
@@ -469,9 +437,7 @@ void handler_read_property_multiple(
|
||||
/* handle an individual property */
|
||||
len = RPM_Encode_Property(
|
||||
&Handler_Transmit_Buffer[npdu_len],
|
||||
(uint16_t)apdu_len,
|
||||
sizeof(Handler_Transmit_Buffer) - npdu_len,
|
||||
&rpmdata);
|
||||
(uint16_t)apdu_len, MAX_APDU, &rpmdata);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
@@ -490,16 +456,15 @@ void handler_read_property_multiple(
|
||||
/* Reached end of property list so cap the result list
|
||||
*/
|
||||
decode_len++;
|
||||
len =
|
||||
rpm_ack_encode_apdu_object_end(&RPM_Prop_Buffer[0]);
|
||||
len = rpm_ack_encode_apdu_object_end(&Temp_Buf[0]);
|
||||
copy_len = memcopy(
|
||||
&Handler_Transmit_Buffer[npdu_len],
|
||||
&RPM_Prop_Buffer[0], apdu_len, len,
|
||||
sizeof(Handler_Transmit_Buffer) - npdu_len);
|
||||
&Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0],
|
||||
apdu_len, len, MAX_APDU);
|
||||
if (copy_len == 0) {
|
||||
debug_print(
|
||||
"RPM: Too full to encode object end!\n");
|
||||
rpmdata.error_code = BACNET_RPM_BUFFER_OVERFLOW;
|
||||
rpmdata.error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
error = BACNET_STATUS_ABORT;
|
||||
/* The berror flag ensures that
|
||||
both loops will be broken! */
|
||||
@@ -522,36 +487,12 @@ void handler_read_property_multiple(
|
||||
}
|
||||
/* If not having an error so far, check the remaining space. */
|
||||
if (!berror) {
|
||||
max_resp = min(service_data->max_resp, MAX_APDU);
|
||||
if (apdu_len > max_resp) {
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
if (service_data->segmented_response_accepted) {
|
||||
apdu_init_fixed_header(
|
||||
&apdu_fixed_header, PDU_TYPE_COMPLEX_ACK,
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_READ_PROP_MULTIPLE,
|
||||
service_data->max_resp);
|
||||
|
||||
npdu_encode_npdu_data(
|
||||
&npdu_data, true, MESSAGE_PRIORITY_NORMAL);
|
||||
npdu_len = npdu_encode_pdu(
|
||||
&Handler_Transmit_Buffer[0], src, &my_address,
|
||||
&npdu_data);
|
||||
|
||||
tsm_set_complexack_transaction(
|
||||
src, &npdu_data, &apdu_fixed_header, service_data,
|
||||
&Handler_Transmit_Buffer
|
||||
[npdu_len + apdu_header_len],
|
||||
(apdu_len - apdu_header_len));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (apdu_len > service_data->max_resp) {
|
||||
/* too big for the sender - send an abort */
|
||||
rpmdata.error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
error = BACNET_STATUS_ABORT;
|
||||
debug_print("RPM: Message too large. Sending Abort!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,16 +107,13 @@ void handler_write_property(
|
||||
REJECT_REASON_MISSING_REQUIRED_PARAMETER);
|
||||
debug_print("WP: Missing Required Parameter. Sending Reject!\n");
|
||||
bcontinue = false;
|
||||
}
|
||||
#if !BACNET_SEGMENTATION_ENABLED
|
||||
else if (service_data->segmented_message) {
|
||||
} else if (service_data->segmented_message) {
|
||||
len = abort_encode_apdu(
|
||||
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
debug_print("WP: Segmented message. Sending Abort!\n");
|
||||
bcontinue = false;
|
||||
}
|
||||
#endif
|
||||
if (bcontinue) {
|
||||
/* decode the service request only */
|
||||
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
||||
|
||||
@@ -141,13 +141,11 @@ void handler_write_property_multiple(
|
||||
len = BACNET_STATUS_REJECT;
|
||||
debug_print("WPM: Missing Required Parameter. "
|
||||
"Sending Reject!\n");
|
||||
#if !BACNET_SEGMENTATION_ENABLED
|
||||
} else if (service_data->segmented_message) {
|
||||
wp_data.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
len = BACNET_STATUS_ABORT;
|
||||
debug_print("WPM: Segmented message. "
|
||||
"Sending Abort!\n");
|
||||
#endif
|
||||
} else {
|
||||
/* first time - detect malformed request before writing any data */
|
||||
len = write_property_multiple_decode(
|
||||
|
||||
@@ -85,7 +85,7 @@ int iam_encode_pdu(
|
||||
/* encode the APDU portion of the packet */
|
||||
len = iam_encode_apdu(
|
||||
&buffer[pdu_len], Device_Object_Instance_Number(), MAX_APDU,
|
||||
Device_Segmentation_Supported(), Device_Vendor_Identifier());
|
||||
SEGMENTATION_NONE, Device_Vendor_Identifier());
|
||||
pdu_len += len;
|
||||
|
||||
return pdu_len;
|
||||
@@ -158,7 +158,7 @@ int iam_unicast_encode_pdu(
|
||||
/* encode the APDU portion of the packet */
|
||||
apdu_len = iam_encode_apdu(
|
||||
&buffer[npdu_len], Device_Object_Instance_Number(), MAX_APDU,
|
||||
Device_Segmentation_Supported(), Device_Vendor_Identifier());
|
||||
SEGMENTATION_NONE, Device_Vendor_Identifier());
|
||||
pdu_len = npdu_len + apdu_len;
|
||||
|
||||
return pdu_len;
|
||||
|
||||
+63
-1243
File diff suppressed because it is too large
Load Diff
+11
-102
@@ -15,9 +15,6 @@
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
#include "bacnet/npdu.h"
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
#include "bacnet/apdu.h"
|
||||
#endif
|
||||
|
||||
/* note: TSM functionality is optional - only needed if we are
|
||||
doing client requests */
|
||||
@@ -27,7 +24,7 @@ extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* FIXME: modify basic service handlers to use TSM rather than this buffer! */
|
||||
BACNET_STACK_EXPORT extern uint8_t Handler_Transmit_Buffer[MAX_ASDU];
|
||||
BACNET_STACK_EXPORT extern uint8_t Handler_Transmit_Buffer[MAX_PDU];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@@ -40,47 +37,31 @@ typedef enum {
|
||||
TSM_STATE_IDLE,
|
||||
TSM_STATE_AWAIT_CONFIRMATION,
|
||||
TSM_STATE_AWAIT_RESPONSE,
|
||||
TSM_STATE_SEGMENTED_REQUEST_SERVER,
|
||||
TSM_STATE_SEGMENTED_CONFIRMATION,
|
||||
TSM_STATE_SEGMENTED_RESPONSE_SERVER
|
||||
TSM_STATE_SEGMENTED_REQUEST,
|
||||
TSM_STATE_SEGMENTED_CONFIRMATION
|
||||
} BACNET_TSM_STATE;
|
||||
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
/* Indirect data state : */
|
||||
typedef struct BACnet_TSM_Indirect_Data {
|
||||
/* the address we received data from */
|
||||
BACNET_ADDRESS PeerAddress;
|
||||
/* the peer unique id */
|
||||
uint8_t PeerInvokeID;
|
||||
/* the unique id to use within our internal states.
|
||||
zero means : "unused slot". */
|
||||
uint8_t InternalInvokeID;
|
||||
} BACNET_TSM_INDIRECT_DATA;
|
||||
#endif
|
||||
|
||||
/* 5.4.1 Variables And Parameters */
|
||||
/* The following variables are defined for each instance of */
|
||||
/* Transaction State Machine: */
|
||||
typedef struct BACnet_TSM_Data {
|
||||
/* used to count APDU retries */
|
||||
uint8_t RetryCount;
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
/* used to count segment retries */
|
||||
uint8_t SegmentRetryCount;
|
||||
/*uint8_t SegmentRetryCount; */
|
||||
/* used to control APDU retries and the acceptance of server replies */
|
||||
bool SentAllSegments;
|
||||
/*bool SentAllSegments; */
|
||||
/* stores the sequence number of the last segment received in order */
|
||||
uint8_t LastSequenceNumber;
|
||||
/*uint8_t LastSequenceNumber; */
|
||||
/* stores the sequence number of the first segment of */
|
||||
/* a sequence of segments that fill a window */
|
||||
uint8_t InitialSequenceNumber;
|
||||
/*uint8_t InitialSequenceNumber; */
|
||||
/* stores the current window size */
|
||||
uint8_t ActualWindowSize;
|
||||
/*uint8_t ActualWindowSize; */
|
||||
/* stores the window size proposed by the segment sender */
|
||||
uint8_t ProposedWindowSize;
|
||||
/*uint8_t ProposedWindowSize; */
|
||||
/* used to perform timeout on PDU segments */
|
||||
uint16_t SegmentTimer;
|
||||
#endif
|
||||
/*uint8_t SegmentTimer; */
|
||||
/* used to perform timeout on Confirmed Requests */
|
||||
/* in milliseconds */
|
||||
uint16_t RequestTimer;
|
||||
@@ -92,28 +73,9 @@ typedef struct BACnet_TSM_Data {
|
||||
BACNET_ADDRESS dest;
|
||||
/* the network layer info */
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
unsigned apdu_len;
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
/* APDU header information */
|
||||
BACNET_APDU_FIXED_HEADER apdu_fixed_header;
|
||||
/* calculated max APDU length / packet */
|
||||
uint32_t apdu_maximum_length;
|
||||
/* calculated max APDU length / total */
|
||||
uint32_t maximum_transmittable_length;
|
||||
/* Multiple APDU segments blob memorized here */
|
||||
uint8_t *apdu_blob;
|
||||
/* Size of allocated Multiple APDU segments blob */
|
||||
uint32_t apdu_blob_allocated;
|
||||
/* Size of data within the multiple APDU segments blob */
|
||||
uint32_t apdu_blob_size;
|
||||
/* Count received segments (prevents D.O.S.) */
|
||||
uint32_t ReceivedSegmentsCount;
|
||||
/* copy of the APDU, should we need to send it again */
|
||||
uint8_t *apdu;
|
||||
#else
|
||||
/* copy of the APDU, should we need to send it again */
|
||||
uint8_t apdu[MAX_PDU];
|
||||
#endif
|
||||
unsigned apdu_len;
|
||||
} BACNET_TSM_DATA;
|
||||
|
||||
typedef void (*tsm_timeout_function)(uint8_t invoke_id);
|
||||
@@ -161,59 +123,6 @@ bool tsm_invoke_id_free(uint8_t invokeID);
|
||||
BACNET_STACK_EXPORT
|
||||
bool tsm_invoke_id_failed(uint8_t invokeID);
|
||||
|
||||
#if BACNET_SEGMENTATION_ENABLED
|
||||
/** Clear TSM Peer data */
|
||||
BACNET_STACK_EXPORT
|
||||
void tsm_clear_peer_id(uint8_t InternalInvokeID);
|
||||
|
||||
/* frees the invokeID and sets its state to IDLE */
|
||||
BACNET_STACK_EXPORT
|
||||
void tsm_free_invoke_id_check(
|
||||
uint8_t invokeID, BACNET_ADDRESS *peer_address, bool cleanup);
|
||||
|
||||
/* Associates a Peer address and invoke ID with our TSM */
|
||||
BACNET_STACK_EXPORT
|
||||
uint8_t tsm_get_peer_id(BACNET_ADDRESS *src, uint8_t invokeID);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool tsm_set_segmented_confirmed_service_received(
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *service_data,
|
||||
uint8_t *internal_invoke_id,
|
||||
uint8_t **pservice_request, /* IN/OUT */
|
||||
uint16_t *pservice_request_len /* IN/OUT */
|
||||
);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int tsm_set_complexack_transaction(
|
||||
BACNET_ADDRESS *dest,
|
||||
BACNET_NPDU_DATA *npdu_data,
|
||||
BACNET_APDU_FIXED_HEADER *apdu_fixed_header,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *confirmed_service_data,
|
||||
uint8_t *pdu,
|
||||
uint32_t pdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void tsm_segmentack_received(
|
||||
uint8_t invoke_id,
|
||||
uint8_t sequence_number,
|
||||
uint8_t actual_window_size,
|
||||
bool nak,
|
||||
bool server,
|
||||
BACNET_ADDRESS *src);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool tsm_is_invalid_apdu_in_this_state(
|
||||
BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_DATA *service_data);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void tsm_abort_pdu_send(
|
||||
uint8_t invoke_id, BACNET_ADDRESS *dest, uint8_t reason, bool server);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void tsm_free_invoke_id_segmentation(BACNET_ADDRESS *src, uint8_t invoke_id);
|
||||
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -164,11 +164,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Enable or disable segmentation support in the library */
|
||||
#ifndef BACNET_SEGMENTATION_ENABLED
|
||||
#define BACNET_SEGMENTATION_ENABLED 0
|
||||
#endif
|
||||
|
||||
/* for confirmed messages, this is the number of transactions */
|
||||
/* that we hold in a queue waiting for timeout. */
|
||||
/* Configure to zero if you don't want any confirmed messages */
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2010 Julien Bennet
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include "segmentack.h"
|
||||
|
||||
/** Method to encode the segment ack .
|
||||
*
|
||||
* @param apdu[in] Pointer to the buffer for encoding.
|
||||
* @param negativeack[in] Acknowedlegment for the segment.
|
||||
* @param server[in] Set to True if the acknowledgment is from the server, else
|
||||
* false.
|
||||
* @param invoke_id[in] Invoke Id
|
||||
* @param sequence_number[in] Sequence number of the segment to be acknowledged
|
||||
* @param actual_window_size[in] Actual window size.
|
||||
*
|
||||
* @return Length of encoded data or zero on error.
|
||||
*/
|
||||
int segmentack_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
bool negativeack,
|
||||
bool server,
|
||||
uint8_t invoke_id,
|
||||
uint8_t sequence_number,
|
||||
uint8_t actual_window_size)
|
||||
{
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
uint8_t server_code = server ? 0x01 : 0x00;
|
||||
uint8_t nak_code = negativeack ? 0x02 : 0x00;
|
||||
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_SEGMENT_ACK | server_code | nak_code;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = sequence_number;
|
||||
apdu[3] = actual_window_size;
|
||||
apdu_len = 4;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/** Method to decode the segment ack service request
|
||||
*
|
||||
* @param apdu[in] The apdu portion of the ACK reply.
|
||||
* @param apdu_len[in] The total length of the apdu.
|
||||
* @param invoke_id[in] Invoke Id of the request.
|
||||
* @param sequence_number[in] Sequence number of the segment received.
|
||||
* @param actual_window_size[in] Actual window size.
|
||||
*
|
||||
* @return Length of decoded data or zero on error.
|
||||
*/
|
||||
int segmentack_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t *sequence_number,
|
||||
uint8_t *actual_window_size)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_header_size = 3;
|
||||
|
||||
if (apdu_len >= apdu_header_size) {
|
||||
if (invoke_id) {
|
||||
*invoke_id = apdu[0];
|
||||
}
|
||||
if (sequence_number) {
|
||||
*sequence_number = apdu[1];
|
||||
}
|
||||
if (actual_window_size) {
|
||||
*actual_window_size = apdu[2];
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2010 Julien Bennet
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef BACNET_SEGMENT_ACK_H
|
||||
#define BACNET_SEGMENT_ACK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bacenum.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacdef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int segmentack_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
bool negativeack,
|
||||
bool server,
|
||||
uint8_t invoke_id,
|
||||
uint8_t sequence_number,
|
||||
uint8_t actual_window_size);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int segmentack_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t *sequence_number,
|
||||
uint8_t *actual_window_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* SEGMENT_ACK_H */
|
||||
Reference in New Issue
Block a user