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
|
### Security
|
||||||
### Added
|
### 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
|
||||||
|
|
||||||
* Changed basic object API for units properties to use BACNET_ENGINEERING_UNITS
|
* Changed basic object API for units properties to use BACNET_ENGINEERING_UNITS
|
||||||
|
|||||||
@@ -84,11 +84,6 @@ option(
|
|||||||
"compile with secure-connect support"
|
"compile with secure-connect support"
|
||||||
OFF)
|
OFF)
|
||||||
|
|
||||||
option(
|
|
||||||
BACNET_SEGMENTATION_ENABLED
|
|
||||||
"enable segmentation"
|
|
||||||
ON)
|
|
||||||
|
|
||||||
if(NOT (BACDL_ETHERNET OR
|
if(NOT (BACDL_ETHERNET OR
|
||||||
BACDL_MSTP OR
|
BACDL_MSTP OR
|
||||||
BACDL_ARCNET OR
|
BACDL_ARCNET OR
|
||||||
@@ -677,8 +672,6 @@ add_library(${PROJECT_NAME}
|
|||||||
src/bacnet/rp.h
|
src/bacnet/rp.h
|
||||||
src/bacnet/rpm.c
|
src/bacnet/rpm.c
|
||||||
src/bacnet/rpm.h
|
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.c
|
||||||
src/bacnet/timer_value.h
|
src/bacnet/timer_value.h
|
||||||
src/bacnet/timestamp.c
|
src/bacnet/timestamp.c
|
||||||
@@ -730,7 +723,6 @@ target_compile_definitions(
|
|||||||
$<$<BOOL:${BACDL_NONE}>:BACDL_NONE>
|
$<$<BOOL:${BACDL_NONE}>:BACDL_NONE>
|
||||||
$<$<BOOL:${BACNET_PROPERTY_LISTS}>:BACNET_PROPERTY_LISTS=1>
|
$<$<BOOL:${BACNET_PROPERTY_LISTS}>:BACNET_PROPERTY_LISTS=1>
|
||||||
$<$<BOOL:${BAC_ROUTING}>:BAC_ROUTING>
|
$<$<BOOL:${BAC_ROUTING}>:BAC_ROUTING>
|
||||||
$<$<BOOL:${BACNET_SEGMENTATION_ENABLED}>:BACNET_SEGMENTATION_ENABLED>
|
|
||||||
$<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:BACNET_STACK_STATIC_DEFINE>
|
$<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:BACNET_STACK_STATIC_DEFINE>
|
||||||
PRIVATE
|
PRIVATE
|
||||||
PRINT_ENABLED=1)
|
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_MSTP:.....................\"${BACDL_MSTP}\"")
|
||||||
message(STATUS "BACNET: BACDL_ZIGBEE:...................\"${BACDL_ZIGBEE}\"")
|
message(STATUS "BACNET: BACDL_ZIGBEE:...................\"${BACDL_ZIGBEE}\"")
|
||||||
message(STATUS "BACNET: BACDL_ETHERNET:.................\"${BACDL_ETHERNET}\"")
|
message(STATUS "BACNET: BACDL_ETHERNET:.................\"${BACDL_ETHERNET}\"")
|
||||||
message(STATUS "BACNET: BACNET_SEGMENTATION_ENABLED:....\"${BACNET_SEGMENTATION_ENABLED}\"")
|
|
||||||
|
|||||||
@@ -224,10 +224,6 @@ server-discover:
|
|||||||
server-mini:
|
server-mini:
|
||||||
$(MAKE) LEGACY=true NOTIFY=false -s -C apps $@
|
$(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
|
.PHONY: sc-hub
|
||||||
sc-hub:
|
sc-hub:
|
||||||
$(MAKE) LEGACY=true BACDL=bsc -s -C apps $@
|
$(MAKE) LEGACY=true BACDL=bsc -s -C apps $@
|
||||||
|
|||||||
@@ -223,11 +223,6 @@ ifeq (${LEGACY},true)
|
|||||||
BACNET_DEFINES += -DBACNET_STACK_DEPRECATED_DISABLE
|
BACNET_DEFINES += -DBACNET_STACK_DEPRECATED_DISABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq (${SEGMENT},true)
|
|
||||||
# enable segmentation support
|
|
||||||
BACNET_DEFINES += -DBACNET_SEGMENTATION_ENABLED=1
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq (${NOTIFY},false)
|
ifeq (${NOTIFY},false)
|
||||||
# disable intrinsic reporting
|
# disable intrinsic reporting
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -174,20 +174,6 @@ static void Init_Service_Handlers(void)
|
|||||||
(unsigned)object_data.object_instance);
|
(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 */
|
/* we need to handle who-is to support dynamic device binding */
|
||||||
apdu_set_unconfirmed_handler(
|
apdu_set_unconfirmed_handler(
|
||||||
SERVICE_UNCONFIRMED_WHO_IS, handler_who_is_who_am_i_unicast);
|
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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
BACNET_SEGMENTATION Device_Segmentation_Supported(void)
|
|
||||||
{
|
|
||||||
return SEGMENTATION_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Device_Valid_Object_Instance_Number(uint32_t object_id)
|
bool Device_Valid_Object_Instance_Number(uint32_t object_id)
|
||||||
{
|
{
|
||||||
/* BACnet allows for a wildcard instance number */
|
/* BACnet allows for a wildcard instance number */
|
||||||
|
|||||||
@@ -32,21 +32,6 @@ typedef struct _confirmed_service_ack_data {
|
|||||||
uint8_t proposed_window_number;
|
uint8_t proposed_window_number;
|
||||||
} BACNET_CONFIRMED_SERVICE_ACK_DATA;
|
} 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);
|
uint8_t apdu_network_priority(void);
|
||||||
void apdu_network_priority_set(uint8_t pri);
|
void apdu_network_priority_set(uint8_t pri);
|
||||||
|
|
||||||
|
|||||||
@@ -212,24 +212,8 @@ typedef struct BACnet_Object_Id {
|
|||||||
uint32_t instance;
|
uint32_t instance;
|
||||||
} BACNET_OBJECT_ID;
|
} 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_NPDU (1 + 1 + 2 + 1 + MAX_MAC_LEN + 2 + 1 + MAX_MAC_LEN + 1 + 1 + 2)
|
||||||
#define MAX_PDU (MAX_APDU + MAX_NPDU)
|
#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) \
|
#define BACNET_ID_VALUE(bacnet_object_instance, bacnet_object_type) \
|
||||||
((((bacnet_object_type) & BACNET_MAX_OBJECT) << BACNET_INSTANCE_BITS) | \
|
((((bacnet_object_type) & BACNET_MAX_OBJECT) << BACNET_INSTANCE_BITS) | \
|
||||||
|
|||||||
@@ -45,10 +45,6 @@ static struct Address_Cache_Entry {
|
|||||||
uint8_t Flags;
|
uint8_t Flags;
|
||||||
uint32_t device_id;
|
uint32_t device_id;
|
||||||
unsigned max_apdu;
|
unsigned max_apdu;
|
||||||
#if BACNET_SEGMENTATION_ENABLED
|
|
||||||
uint8_t segmentation;
|
|
||||||
uint16_t maxsegments;
|
|
||||||
#endif
|
|
||||||
BACNET_ADDRESS address;
|
BACNET_ADDRESS address;
|
||||||
uint32_t TimeToLive;
|
uint32_t TimeToLive;
|
||||||
} Address_Cache[MAX_ADDRESS_CACHE];
|
} Address_Cache[MAX_ADDRESS_CACHE];
|
||||||
@@ -350,16 +346,9 @@ void address_set_device_TTL(
|
|||||||
* @param device_id Device-Id
|
* @param device_id Device-Id
|
||||||
* @param max_apdu Pointer to a variable, taking the maximum APDU size.
|
* @param max_apdu Pointer to a variable, taking the maximum APDU size.
|
||||||
* @param src Pointer to address structure for return.
|
* @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(
|
bool address_get_by_device(
|
||||||
uint32_t device_id,
|
uint32_t device_id, unsigned *max_apdu, BACNET_ADDRESS *src)
|
||||||
unsigned *max_apdu,
|
|
||||||
BACNET_ADDRESS *src,
|
|
||||||
uint8_t *segmentation,
|
|
||||||
uint16_t *maxsegments)
|
|
||||||
{
|
{
|
||||||
struct Address_Cache_Entry *pMatch;
|
struct Address_Cache_Entry *pMatch;
|
||||||
bool found = false; /* return value */
|
bool found = false; /* return value */
|
||||||
@@ -375,20 +364,6 @@ bool address_segment_get_by_device(
|
|||||||
if (max_apdu) {
|
if (max_apdu) {
|
||||||
*max_apdu = pMatch->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 */
|
/* Prove we found it */
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
@@ -400,19 +375,6 @@ bool address_segment_get_by_device(
|
|||||||
return found;
|
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.
|
* Find a device id from a given MAC address.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -43,14 +43,6 @@ BACNET_STACK_EXPORT
|
|||||||
bool address_get_by_device(
|
bool address_get_by_device(
|
||||||
uint32_t device_id, unsigned *max_apdu, BACNET_ADDRESS *src);
|
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
|
BACNET_STACK_EXPORT
|
||||||
bool address_get_by_index(
|
bool address_get_by_index(
|
||||||
unsigned index,
|
unsigned index,
|
||||||
|
|||||||
@@ -1145,11 +1145,7 @@ uint8_t Device_Protocol_Revision(void)
|
|||||||
|
|
||||||
BACNET_SEGMENTATION Device_Segmentation_Supported(void)
|
BACNET_SEGMENTATION Device_Segmentation_Supported(void)
|
||||||
{
|
{
|
||||||
#if BACNET_SEGMENTATION_ENABLED
|
|
||||||
return SEGMENTATION_BOTH;
|
|
||||||
#else
|
|
||||||
return SEGMENTATION_NONE;
|
return SEGMENTATION_NONE;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1620,12 +1616,8 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
|||||||
rpdata->object_instance, rpdata->array_index,
|
rpdata->object_instance, rpdata->array_index,
|
||||||
Device_Object_List_Element_Encode, count, apdu, apdu_max);
|
Device_Object_List_Element_Encode, count, apdu, apdu_max);
|
||||||
if (apdu_len == BACNET_STATUS_ABORT) {
|
if (apdu_len == BACNET_STATUS_ABORT) {
|
||||||
#if BACNET_SEGMENTATION_ENABLED
|
|
||||||
rpdata->error_code = ERROR_CODE_ABORT_BUFFER_OVERFLOW;
|
|
||||||
#else
|
|
||||||
rpdata->error_code =
|
rpdata->error_code =
|
||||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
#endif
|
|
||||||
} else if (apdu_len == BACNET_STATUS_ERROR) {
|
} else if (apdu_len == BACNET_STATUS_ERROR) {
|
||||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||||
|
|||||||
@@ -26,10 +26,6 @@ static uint16_t Timeout_Milliseconds = 3000;
|
|||||||
/* Number of APDU Retries */
|
/* Number of APDU Retries */
|
||||||
static uint8_t Number_Of_Retries = 3;
|
static uint8_t Number_Of_Retries = 3;
|
||||||
static uint8_t Local_Network_Priority; /* Fixing test 10.1.2 Network priority */
|
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 */
|
/* a simple table for crossing the services supported */
|
||||||
static BACNET_SERVICES_SUPPORTED
|
static BACNET_SERVICES_SUPPORTED
|
||||||
@@ -556,109 +552,6 @@ static bool apdu_unconfirmed_dcc_disabled(uint8_t service_choice)
|
|||||||
return status;
|
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
|
/** Process the APDU header and invoke the appropriate service handler
|
||||||
* to manage the received request.
|
* to manage the received request.
|
||||||
* Almost all requests and ACKs invoke this function.
|
* Almost all requests and ACKs invoke this function.
|
||||||
@@ -674,15 +567,11 @@ void apdu_handler(
|
|||||||
uint16_t apdu_len)
|
uint16_t apdu_len)
|
||||||
{
|
{
|
||||||
BACNET_PDU_TYPE pdu_type;
|
BACNET_PDU_TYPE pdu_type;
|
||||||
|
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||||
uint8_t service_choice = 0;
|
uint8_t service_choice = 0;
|
||||||
uint8_t *service_request = NULL;
|
uint8_t *service_request = NULL;
|
||||||
uint16_t service_request_len = 0;
|
uint16_t service_request_len = 0;
|
||||||
int len = 0; /* counts where we are in PDU */
|
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
|
#if !BACNET_SVC_SERVER
|
||||||
uint8_t invoke_id = 0;
|
uint8_t invoke_id = 0;
|
||||||
BACNET_CONFIRMED_SERVICE_ACK_DATA service_ack_data = { 0 };
|
BACNET_CONFIRMED_SERVICE_ACK_DATA service_ack_data = { 0 };
|
||||||
@@ -701,14 +590,27 @@ void apdu_handler(
|
|||||||
pdu_type = apdu[0] & 0xF0;
|
pdu_type = apdu[0] & 0xF0;
|
||||||
switch (pdu_type) {
|
switch (pdu_type) {
|
||||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||||
/* segmented_message_reception ? */
|
len = apdu_decode_confirmed_service_request(
|
||||||
#if BACNET_SEGMENTATION_ENABLED
|
apdu, apdu_len, &service_data, &service_choice,
|
||||||
if (apdu[0] & BIT(3)) {
|
&service_request, &service_request_len);
|
||||||
apdu_handler_confirmed_service_segment(src, apdu, apdu_len);
|
if (len == 0) {
|
||||||
} else
|
/* service data unable to be decoded - simply drop */
|
||||||
#endif
|
break;
|
||||||
{
|
}
|
||||||
apdu_handler_confirmed_service(src, apdu, apdu_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. */
|
||||||
|
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;
|
break;
|
||||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||||
@@ -783,24 +685,9 @@ void apdu_handler(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PDU_TYPE_SEGMENT_ACK:
|
case PDU_TYPE_SEGMENT_ACK:
|
||||||
#if !BACNET_SEGMENTATION_ENABLED
|
|
||||||
/* FIXME: what about a denial of service attack here?
|
/* FIXME: what about a denial of service attack here?
|
||||||
we could check src to see if that matched the tsm */
|
we could check src to see if that matched the tsm */
|
||||||
tsm_free_invoke_id(invoke_id);
|
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;
|
break;
|
||||||
case PDU_TYPE_ERROR:
|
case PDU_TYPE_ERROR:
|
||||||
if (apdu_len < 3) {
|
if (apdu_len < 3) {
|
||||||
@@ -827,12 +714,7 @@ void apdu_handler(
|
|||||||
(BACNET_ERROR_CODE)error_code);
|
(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);
|
tsm_free_invoke_id(invoke_id);
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case PDU_TYPE_REJECT:
|
case PDU_TYPE_REJECT:
|
||||||
if (apdu_len < 3) {
|
if (apdu_len < 3) {
|
||||||
@@ -843,12 +725,7 @@ void apdu_handler(
|
|||||||
if (Reject_Function) {
|
if (Reject_Function) {
|
||||||
Reject_Function(src, invoke_id, reason);
|
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);
|
tsm_free_invoke_id(invoke_id);
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case PDU_TYPE_ABORT:
|
case PDU_TYPE_ABORT:
|
||||||
if (apdu_len < 3) {
|
if (apdu_len < 3) {
|
||||||
@@ -857,156 +734,13 @@ void apdu_handler(
|
|||||||
server = apdu[0] & 0x01;
|
server = apdu[0] & 0x01;
|
||||||
invoke_id = apdu[1];
|
invoke_id = apdu[1];
|
||||||
reason = apdu[2];
|
reason = apdu[2];
|
||||||
if (!server) {
|
if (Abort_Function) {
|
||||||
/*AbortPDU_Received*/
|
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);
|
tsm_free_invoke_id(invoke_id);
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
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 */
|
uint8_t *apdu, /* APDU data */
|
||||||
uint16_t pdu_len); /* for confirmed messages */
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@@ -108,9 +108,7 @@ void handler_device_communication_control(
|
|||||||
debug_print("DeviceCommunicationControl: "
|
debug_print("DeviceCommunicationControl: "
|
||||||
"Missing Required Parameter. Sending Reject!\n");
|
"Missing Required Parameter. Sending Reject!\n");
|
||||||
goto DCC_FAILURE;
|
goto DCC_FAILURE;
|
||||||
}
|
} else if (service_data->segmented_message) {
|
||||||
#if !BACNET_SEGMENTATION_ENABLED
|
|
||||||
else if (service_data->segmented_message) {
|
|
||||||
len = abort_encode_apdu(
|
len = abort_encode_apdu(
|
||||||
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
|
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
|
||||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||||
@@ -118,7 +116,6 @@ void handler_device_communication_control(
|
|||||||
"Sending Abort - segmented message.\n");
|
"Sending Abort - segmented message.\n");
|
||||||
goto DCC_FAILURE;
|
goto DCC_FAILURE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
/* decode the service request only */
|
/* decode the service request only */
|
||||||
len = dcc_decode_service_request(
|
len = dcc_decode_service_request(
|
||||||
service_request, service_len, &timeDuration, &state, &password);
|
service_request, service_len, &timeDuration, &state, &password);
|
||||||
|
|||||||
@@ -71,16 +71,13 @@ void handler_reinitialize_device(
|
|||||||
debug_print("ReinitializeDevice: Missing Required Parameter. "
|
debug_print("ReinitializeDevice: Missing Required Parameter. "
|
||||||
"Sending Reject!\n");
|
"Sending Reject!\n");
|
||||||
goto RD_ABORT;
|
goto RD_ABORT;
|
||||||
}
|
} else if (service_data->segmented_message) {
|
||||||
#if !BACNET_SEGMENTATION_ENABLED
|
|
||||||
else if (service_data->segmented_message) {
|
|
||||||
len = abort_encode_apdu(
|
len = abort_encode_apdu(
|
||||||
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
|
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
|
||||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||||
debug_print("ReinitializeDevice: Sending Abort - segmented message.\n");
|
debug_print("ReinitializeDevice: Sending Abort - segmented message.\n");
|
||||||
goto RD_ABORT;
|
goto RD_ABORT;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
/* decode the service request only */
|
/* decode the service request only */
|
||||||
len = rd_decode_service_request(
|
len = rd_decode_service_request(
|
||||||
service_request, service_len, &rd_data.state, &rd_data.password);
|
service_request, service_len, &rd_data.state, &rd_data.password);
|
||||||
|
|||||||
@@ -30,12 +30,6 @@
|
|||||||
#include "bacnet/basic/sys/debug.h"
|
#include "bacnet/basic/sys/debug.h"
|
||||||
#include "bacnet/datalink/datalink.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. */
|
/** @file h_rp.c Handles Read Property requests. */
|
||||||
|
|
||||||
/** Handler for a ReadProperty Service request.
|
/** Handler for a ReadProperty Service request.
|
||||||
@@ -44,7 +38,7 @@
|
|||||||
* by a call to apdu_set_confirmed_handler().
|
* by a call to apdu_set_confirmed_handler().
|
||||||
* This handler builds a response packet, which is
|
* This handler builds a response packet, which is
|
||||||
* - an Abort if
|
* - an Abort if
|
||||||
* - the message is segmented and segmentation is not supported
|
* - the message is segmented
|
||||||
* - if decoding fails
|
* - if decoding fails
|
||||||
* - if the response would be too large
|
* - if the response would be too large
|
||||||
* - the result from Device_Read_Property(), if it succeeds
|
* - the result from Device_Read_Property(), if it succeeds
|
||||||
@@ -65,7 +59,6 @@ void handler_read_property(
|
|||||||
{
|
{
|
||||||
BACNET_READ_PROPERTY_DATA rpdata;
|
BACNET_READ_PROPERTY_DATA rpdata;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int max_resp = 0;
|
|
||||||
int pdu_len = 0;
|
int pdu_len = 0;
|
||||||
int apdu_len = -1;
|
int apdu_len = -1;
|
||||||
int npdu_len = -1;
|
int npdu_len = -1;
|
||||||
@@ -73,13 +66,9 @@ void handler_read_property(
|
|||||||
bool error = true; /* assume that there is an error */
|
bool error = true; /* assume that there is an error */
|
||||||
int bytes_sent = 0;
|
int bytes_sent = 0;
|
||||||
BACNET_ADDRESS my_address;
|
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 */
|
/* 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 */
|
/* encode the NPDU portion of the packet */
|
||||||
datalink_get_my_address(&my_address);
|
datalink_get_my_address(&my_address);
|
||||||
npdu_encode_npdu_data(&npdu_data, false, service_data->priority);
|
npdu_encode_npdu_data(&npdu_data, false, service_data->priority);
|
||||||
@@ -93,12 +82,10 @@ void handler_read_property(
|
|||||||
len = BACNET_STATUS_REJECT;
|
len = BACNET_STATUS_REJECT;
|
||||||
rpdata.error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
rpdata.error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||||
debug_print("RP: Missing Required Parameter. Sending Reject!\n");
|
debug_print("RP: Missing Required Parameter. Sending Reject!\n");
|
||||||
#if !BACNET_SEGMENTATION_ENABLED
|
|
||||||
} else if (service_data->segmented_message) {
|
} else if (service_data->segmented_message) {
|
||||||
/* we don't support segmentation - send an abort */
|
/* we don't support segmentation - send an abort */
|
||||||
len = BACNET_STATUS_ABORT;
|
len = BACNET_STATUS_ABORT;
|
||||||
debug_print("RP: Segmented message. Sending Abort!\n");
|
debug_print("RP: Segmented message. Sending Abort!\n");
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
len = rp_decode_service_request(service_request, service_len, &rpdata);
|
len = rp_decode_service_request(service_request, service_len, &rpdata);
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
@@ -129,13 +116,6 @@ void handler_read_property(
|
|||||||
rpdata.object_instance = Network_Port_Index_To_Instance(0);
|
rpdata.object_instance = Network_Port_Index_To_Instance(0);
|
||||||
}
|
}
|
||||||
#endif
|
#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(
|
apdu_len = rp_ack_encode_apdu_init(
|
||||||
&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id,
|
&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id,
|
||||||
&rpdata);
|
&rpdata);
|
||||||
@@ -154,25 +134,7 @@ void handler_read_property(
|
|||||||
len = rp_ack_encode_apdu_object_property_end(
|
len = rp_ack_encode_apdu_object_property_end(
|
||||||
&Handler_Transmit_Buffer[npdu_len + apdu_len]);
|
&Handler_Transmit_Buffer[npdu_len + apdu_len]);
|
||||||
apdu_len += len;
|
apdu_len += len;
|
||||||
/* pick the smaller response packet: ours or theirs */
|
if (apdu_len > service_data->max_resp) {
|
||||||
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
|
|
||||||
/* too big for the sender - send an abort!
|
/* too big for the sender - send an abort!
|
||||||
Setting of error code needed here as read property
|
Setting of error code needed here as read property
|
||||||
processing may have overridden the default set at start
|
processing may have overridden the default set at start
|
||||||
@@ -181,7 +143,6 @@ void handler_read_property(
|
|||||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
len = BACNET_STATUS_ABORT;
|
len = BACNET_STATUS_ABORT;
|
||||||
debug_print("RP: Message too large.\n");
|
debug_print("RP: Message too large.\n");
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
debug_print("RP: Sending Ack!\n");
|
debug_print("RP: Sending Ack!\n");
|
||||||
error = false;
|
error = false;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
|
||||||
/* BACnet Stack defines - first */
|
/* BACnet Stack defines - first */
|
||||||
#include "bacnet/bacdef.h"
|
#include "bacnet/bacdef.h"
|
||||||
/* BACnet Stack API */
|
/* BACnet Stack API */
|
||||||
@@ -34,17 +33,7 @@
|
|||||||
#include "bacnet/basic/sys/debug.h"
|
#include "bacnet/basic/sys/debug.h"
|
||||||
#include "bacnet/datalink/datalink.h"
|
#include "bacnet/datalink/datalink.h"
|
||||||
|
|
||||||
/* Smaller single threaded implementations prefer a
|
static uint8_t Temp_Buf[MAX_APDU] = { 0 };
|
||||||
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
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Fetches the lists of properties (array of BACNET_PROPERTY_ID's) for
|
* @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;
|
size_t copy_len = 0;
|
||||||
int apdu_len = 0;
|
int apdu_len = 0;
|
||||||
BACNET_READ_PROPERTY_DATA rpdata;
|
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(
|
len = rpm_ack_encode_apdu_object_property(
|
||||||
&RPM_Prop_Buffer[0], rpmdata->object_property, rpmdata->array_index);
|
&Temp_Buf[0], rpmdata->object_property, rpmdata->array_index);
|
||||||
copy_len = memcopy(&apdu[0], &RPM_Prop_Buffer[0], offset, len, max_apdu);
|
copy_len = memcopy(&apdu[0], &Temp_Buf[0], offset, len, max_apdu);
|
||||||
if (copy_len == 0) {
|
if (copy_len == 0) {
|
||||||
rpmdata->error_code = BACNET_RPM_BUFFER_OVERFLOW;
|
rpmdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
return BACNET_STATUS_ABORT;
|
return BACNET_STATUS_ABORT;
|
||||||
}
|
}
|
||||||
apdu_len += len;
|
apdu_len += len;
|
||||||
@@ -153,8 +139,8 @@ static int RPM_Encode_Property(
|
|||||||
rpdata.object_instance = rpmdata->object_instance;
|
rpdata.object_instance = rpmdata->object_instance;
|
||||||
rpdata.object_property = rpmdata->object_property;
|
rpdata.object_property = rpmdata->object_property;
|
||||||
rpdata.array_index = rpmdata->array_index;
|
rpdata.array_index = rpmdata->array_index;
|
||||||
rpdata.application_data = &RPM_Prop_Buffer[0];
|
rpdata.application_data = &Temp_Buf[0];
|
||||||
rpdata.application_data_len = sizeof(RPM_Prop_Buffer);
|
rpdata.application_data_len = sizeof(Temp_Buf);
|
||||||
|
|
||||||
if ((rpmdata->object_property == PROP_ALL) ||
|
if ((rpmdata->object_property == PROP_ALL) ||
|
||||||
(rpmdata->object_property == PROP_REQUIRED) ||
|
(rpmdata->object_property == PROP_REQUIRED) ||
|
||||||
@@ -175,21 +161,21 @@ static int RPM_Encode_Property(
|
|||||||
}
|
}
|
||||||
/* error was returned - encode that for the response */
|
/* error was returned - encode that for the response */
|
||||||
len = rpm_ack_encode_apdu_object_property_error(
|
len = rpm_ack_encode_apdu_object_property_error(
|
||||||
&RPM_Prop_Buffer[0], rpdata.error_class, rpdata.error_code);
|
&Temp_Buf[0], rpdata.error_class, rpdata.error_code);
|
||||||
copy_len = memcopy(
|
copy_len =
|
||||||
&apdu[0], &RPM_Prop_Buffer[0], offset + apdu_len, len, max_apdu);
|
memcopy(&apdu[0], &Temp_Buf[0], offset + apdu_len, len, max_apdu);
|
||||||
|
|
||||||
if (copy_len == 0) {
|
if (copy_len == 0) {
|
||||||
rpmdata->error_code = BACNET_RPM_BUFFER_OVERFLOW;
|
rpmdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
return BACNET_STATUS_ABORT;
|
return BACNET_STATUS_ABORT;
|
||||||
}
|
}
|
||||||
} else if ((offset + apdu_len + 1 + len + 1) < max_apdu) {
|
} else if ((offset + apdu_len + 1 + len + 1) < max_apdu) {
|
||||||
/* enough room to fit the property value and tags */
|
/* enough room to fit the property value and tags */
|
||||||
len = rpm_ack_encode_apdu_object_property_value(
|
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 {
|
} else {
|
||||||
/* not enough room - abort! */
|
/* not enough room - abort! */
|
||||||
rpmdata->error_code = BACNET_RPM_BUFFER_OVERFLOW;
|
rpmdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
return BACNET_STATUS_ABORT;
|
return BACNET_STATUS_ABORT;
|
||||||
}
|
}
|
||||||
apdu_len += len;
|
apdu_len += len;
|
||||||
@@ -203,7 +189,7 @@ static int RPM_Encode_Property(
|
|||||||
* by a call to apdu_set_confirmed_handler().
|
* by a call to apdu_set_confirmed_handler().
|
||||||
* This handler builds a response packet, which is
|
* This handler builds a response packet, which is
|
||||||
* - an Abort if
|
* - an Abort if
|
||||||
* - the message is segmented and SEGMENTATION_NONE
|
* - the message is segmented
|
||||||
* - if decoding fails
|
* - if decoding fails
|
||||||
* - if the response would be too large
|
* - if the response would be too large
|
||||||
* - the result from each included read request, if it succeeds
|
* - the result from each included read request, if it succeeds
|
||||||
@@ -234,14 +220,6 @@ void handler_read_property_multiple(
|
|||||||
int apdu_len = 0;
|
int apdu_len = 0;
|
||||||
int npdu_len = 0;
|
int npdu_len = 0;
|
||||||
int error = 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) {
|
if (service_data) {
|
||||||
datalink_get_my_address(&my_address);
|
datalink_get_my_address(&my_address);
|
||||||
@@ -252,12 +230,10 @@ void handler_read_property_multiple(
|
|||||||
rpmdata.error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
rpmdata.error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||||
error = BACNET_STATUS_REJECT;
|
error = BACNET_STATUS_REJECT;
|
||||||
debug_print("RPM: Missing Required Parameter. Sending Reject!\n");
|
debug_print("RPM: Missing Required Parameter. Sending Reject!\n");
|
||||||
#if !BACNET_SEGMENTATION_ENABLED
|
|
||||||
} else if (service_data->segmented_message) {
|
} else if (service_data->segmented_message) {
|
||||||
rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
error = BACNET_STATUS_ABORT;
|
error = BACNET_STATUS_ABORT;
|
||||||
debug_print("RPM: Segmented message. Sending Abort!\r\n");
|
debug_print("RPM: Segmented message. Sending Abort!\r\n");
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
/* decode apdu request & encode apdu reply
|
/* decode apdu request & encode apdu reply
|
||||||
encode complex ack, invoke id, service choice */
|
encode complex ack, invoke id, service choice */
|
||||||
@@ -303,14 +279,14 @@ void handler_read_property_multiple(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Stick this object id into the reply - if it will fit */
|
/* Stick this object id into the reply - if it will fit */
|
||||||
len = rpm_ack_encode_apdu_object_begin(
|
len = rpm_ack_encode_apdu_object_begin(&Temp_Buf[0], &rpmdata);
|
||||||
&RPM_Prop_Buffer[0], &rpmdata);
|
|
||||||
copy_len = memcopy(
|
copy_len = memcopy(
|
||||||
&Handler_Transmit_Buffer[npdu_len], &RPM_Prop_Buffer[0],
|
&Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], apdu_len,
|
||||||
apdu_len, len, sizeof(RPM_Prop_Buffer));
|
len, MAX_APDU);
|
||||||
if (copy_len == 0) {
|
if (copy_len == 0) {
|
||||||
debug_print("RPM: Response too big!\n");
|
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;
|
error = BACNET_STATUS_ABORT;
|
||||||
berror = true;
|
berror = true;
|
||||||
break;
|
break;
|
||||||
@@ -345,9 +321,7 @@ void handler_read_property_multiple(
|
|||||||
rpmdata.object_type, rpmdata.object_instance)) {
|
rpmdata.object_type, rpmdata.object_instance)) {
|
||||||
len = RPM_Encode_Property(
|
len = RPM_Encode_Property(
|
||||||
&Handler_Transmit_Buffer[npdu_len],
|
&Handler_Transmit_Buffer[npdu_len],
|
||||||
(uint16_t)apdu_len,
|
(uint16_t)apdu_len, MAX_APDU, &rpmdata);
|
||||||
sizeof(Handler_Transmit_Buffer) - npdu_len,
|
|
||||||
&rpmdata);
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
apdu_len += len;
|
apdu_len += len;
|
||||||
} else {
|
} else {
|
||||||
@@ -362,18 +336,18 @@ void handler_read_property_multiple(
|
|||||||
/* No array index options for this special property.
|
/* No array index options for this special property.
|
||||||
Encode error for this object property response */
|
Encode error for this object property response */
|
||||||
len = rpm_ack_encode_apdu_object_property(
|
len = rpm_ack_encode_apdu_object_property(
|
||||||
&RPM_Prop_Buffer[0], rpmdata.object_property,
|
&Temp_Buf[0], rpmdata.object_property,
|
||||||
rpmdata.array_index);
|
rpmdata.array_index);
|
||||||
|
|
||||||
copy_len = memcopy(
|
copy_len = memcopy(
|
||||||
&Handler_Transmit_Buffer[npdu_len],
|
&Handler_Transmit_Buffer[npdu_len],
|
||||||
&RPM_Prop_Buffer[0], apdu_len, len,
|
&Temp_Buf[0], apdu_len, len, MAX_APDU);
|
||||||
sizeof(RPM_Prop_Buffer));
|
|
||||||
|
|
||||||
if (copy_len == 0) {
|
if (copy_len == 0) {
|
||||||
debug_print(
|
debug_print(
|
||||||
"RPM: Too full to encode property!\n");
|
"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;
|
error = BACNET_STATUS_ABORT;
|
||||||
/* The berror flag ensures that
|
/* The berror flag ensures that
|
||||||
both loops will be broken! */
|
both loops will be broken! */
|
||||||
@@ -383,17 +357,17 @@ void handler_read_property_multiple(
|
|||||||
|
|
||||||
apdu_len += len;
|
apdu_len += len;
|
||||||
len = rpm_ack_encode_apdu_object_property_error(
|
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);
|
ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY);
|
||||||
|
|
||||||
copy_len = memcopy(
|
copy_len = memcopy(
|
||||||
&Handler_Transmit_Buffer[npdu_len],
|
&Handler_Transmit_Buffer[npdu_len],
|
||||||
&RPM_Prop_Buffer[0], apdu_len, len,
|
&Temp_Buf[0], apdu_len, len, MAX_APDU);
|
||||||
sizeof(RPM_Prop_Buffer));
|
|
||||||
|
|
||||||
if (copy_len == 0) {
|
if (copy_len == 0) {
|
||||||
debug_print("RPM: Too full to encode error!\n");
|
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;
|
error = BACNET_STATUS_ABORT;
|
||||||
/* The berror flag ensures that
|
/* The berror flag ensures that
|
||||||
both loops will be broken! */
|
both loops will be broken! */
|
||||||
@@ -422,10 +396,7 @@ void handler_read_property_multiple(
|
|||||||
rpmdata.object_instance)) {
|
rpmdata.object_instance)) {
|
||||||
len = RPM_Encode_Property(
|
len = RPM_Encode_Property(
|
||||||
&Handler_Transmit_Buffer[npdu_len],
|
&Handler_Transmit_Buffer[npdu_len],
|
||||||
(uint16_t)apdu_len,
|
(uint16_t)apdu_len, MAX_APDU, &rpmdata);
|
||||||
sizeof(Handler_Transmit_Buffer) -
|
|
||||||
npdu_len,
|
|
||||||
&rpmdata);
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
apdu_len += len;
|
apdu_len += len;
|
||||||
} else {
|
} else {
|
||||||
@@ -447,10 +418,7 @@ void handler_read_property_multiple(
|
|||||||
special_object_property, index);
|
special_object_property, index);
|
||||||
len = RPM_Encode_Property(
|
len = RPM_Encode_Property(
|
||||||
&Handler_Transmit_Buffer[npdu_len],
|
&Handler_Transmit_Buffer[npdu_len],
|
||||||
(uint16_t)apdu_len,
|
(uint16_t)apdu_len, MAX_APDU, &rpmdata);
|
||||||
sizeof(Handler_Transmit_Buffer) -
|
|
||||||
npdu_len,
|
|
||||||
&rpmdata);
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
apdu_len += len;
|
apdu_len += len;
|
||||||
} else {
|
} else {
|
||||||
@@ -469,9 +437,7 @@ void handler_read_property_multiple(
|
|||||||
/* handle an individual property */
|
/* handle an individual property */
|
||||||
len = RPM_Encode_Property(
|
len = RPM_Encode_Property(
|
||||||
&Handler_Transmit_Buffer[npdu_len],
|
&Handler_Transmit_Buffer[npdu_len],
|
||||||
(uint16_t)apdu_len,
|
(uint16_t)apdu_len, MAX_APDU, &rpmdata);
|
||||||
sizeof(Handler_Transmit_Buffer) - npdu_len,
|
|
||||||
&rpmdata);
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
apdu_len += len;
|
apdu_len += len;
|
||||||
} else {
|
} else {
|
||||||
@@ -490,16 +456,15 @@ void handler_read_property_multiple(
|
|||||||
/* Reached end of property list so cap the result list
|
/* Reached end of property list so cap the result list
|
||||||
*/
|
*/
|
||||||
decode_len++;
|
decode_len++;
|
||||||
len =
|
len = rpm_ack_encode_apdu_object_end(&Temp_Buf[0]);
|
||||||
rpm_ack_encode_apdu_object_end(&RPM_Prop_Buffer[0]);
|
|
||||||
copy_len = memcopy(
|
copy_len = memcopy(
|
||||||
&Handler_Transmit_Buffer[npdu_len],
|
&Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0],
|
||||||
&RPM_Prop_Buffer[0], apdu_len, len,
|
apdu_len, len, MAX_APDU);
|
||||||
sizeof(Handler_Transmit_Buffer) - npdu_len);
|
|
||||||
if (copy_len == 0) {
|
if (copy_len == 0) {
|
||||||
debug_print(
|
debug_print(
|
||||||
"RPM: Too full to encode object end!\n");
|
"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;
|
error = BACNET_STATUS_ABORT;
|
||||||
/* The berror flag ensures that
|
/* The berror flag ensures that
|
||||||
both loops will be broken! */
|
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 not having an error so far, check the remaining space. */
|
||||||
if (!berror) {
|
if (!berror) {
|
||||||
max_resp = min(service_data->max_resp, MAX_APDU);
|
if (apdu_len > service_data->max_resp) {
|
||||||
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
|
|
||||||
/* too big for the sender - send an abort */
|
/* too big for the sender - send an abort */
|
||||||
rpmdata.error_code =
|
rpmdata.error_code =
|
||||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
error = BACNET_STATUS_ABORT;
|
error = BACNET_STATUS_ABORT;
|
||||||
debug_print("RPM: Message too large. Sending Abort!\n");
|
debug_print("RPM: Message too large. Sending Abort!\n");
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,16 +107,13 @@ void handler_write_property(
|
|||||||
REJECT_REASON_MISSING_REQUIRED_PARAMETER);
|
REJECT_REASON_MISSING_REQUIRED_PARAMETER);
|
||||||
debug_print("WP: Missing Required Parameter. Sending Reject!\n");
|
debug_print("WP: Missing Required Parameter. Sending Reject!\n");
|
||||||
bcontinue = false;
|
bcontinue = false;
|
||||||
}
|
} else if (service_data->segmented_message) {
|
||||||
#if !BACNET_SEGMENTATION_ENABLED
|
|
||||||
else if (service_data->segmented_message) {
|
|
||||||
len = abort_encode_apdu(
|
len = abort_encode_apdu(
|
||||||
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
|
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
|
||||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||||
debug_print("WP: Segmented message. Sending Abort!\n");
|
debug_print("WP: Segmented message. Sending Abort!\n");
|
||||||
bcontinue = false;
|
bcontinue = false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (bcontinue) {
|
if (bcontinue) {
|
||||||
/* decode the service request only */
|
/* decode the service request only */
|
||||||
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
||||||
|
|||||||
@@ -141,13 +141,11 @@ void handler_write_property_multiple(
|
|||||||
len = BACNET_STATUS_REJECT;
|
len = BACNET_STATUS_REJECT;
|
||||||
debug_print("WPM: Missing Required Parameter. "
|
debug_print("WPM: Missing Required Parameter. "
|
||||||
"Sending Reject!\n");
|
"Sending Reject!\n");
|
||||||
#if !BACNET_SEGMENTATION_ENABLED
|
|
||||||
} else if (service_data->segmented_message) {
|
} else if (service_data->segmented_message) {
|
||||||
wp_data.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
wp_data.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
len = BACNET_STATUS_ABORT;
|
len = BACNET_STATUS_ABORT;
|
||||||
debug_print("WPM: Segmented message. "
|
debug_print("WPM: Segmented message. "
|
||||||
"Sending Abort!\n");
|
"Sending Abort!\n");
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
/* first time - detect malformed request before writing any data */
|
/* first time - detect malformed request before writing any data */
|
||||||
len = write_property_multiple_decode(
|
len = write_property_multiple_decode(
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ int iam_encode_pdu(
|
|||||||
/* encode the APDU portion of the packet */
|
/* encode the APDU portion of the packet */
|
||||||
len = iam_encode_apdu(
|
len = iam_encode_apdu(
|
||||||
&buffer[pdu_len], Device_Object_Instance_Number(), MAX_APDU,
|
&buffer[pdu_len], Device_Object_Instance_Number(), MAX_APDU,
|
||||||
Device_Segmentation_Supported(), Device_Vendor_Identifier());
|
SEGMENTATION_NONE, Device_Vendor_Identifier());
|
||||||
pdu_len += len;
|
pdu_len += len;
|
||||||
|
|
||||||
return pdu_len;
|
return pdu_len;
|
||||||
@@ -158,7 +158,7 @@ int iam_unicast_encode_pdu(
|
|||||||
/* encode the APDU portion of the packet */
|
/* encode the APDU portion of the packet */
|
||||||
apdu_len = iam_encode_apdu(
|
apdu_len = iam_encode_apdu(
|
||||||
&buffer[npdu_len], Device_Object_Instance_Number(), MAX_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;
|
pdu_len = npdu_len + apdu_len;
|
||||||
|
|
||||||
return pdu_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"
|
#include "bacnet/bacdef.h"
|
||||||
/* BACnet Stack API */
|
/* BACnet Stack API */
|
||||||
#include "bacnet/npdu.h"
|
#include "bacnet/npdu.h"
|
||||||
#if BACNET_SEGMENTATION_ENABLED
|
|
||||||
#include "bacnet/apdu.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* note: TSM functionality is optional - only needed if we are
|
/* note: TSM functionality is optional - only needed if we are
|
||||||
doing client requests */
|
doing client requests */
|
||||||
@@ -27,7 +24,7 @@ extern "C" {
|
|||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
/* FIXME: modify basic service handlers to use TSM rather than this buffer! */
|
/* 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@@ -40,47 +37,31 @@ typedef enum {
|
|||||||
TSM_STATE_IDLE,
|
TSM_STATE_IDLE,
|
||||||
TSM_STATE_AWAIT_CONFIRMATION,
|
TSM_STATE_AWAIT_CONFIRMATION,
|
||||||
TSM_STATE_AWAIT_RESPONSE,
|
TSM_STATE_AWAIT_RESPONSE,
|
||||||
TSM_STATE_SEGMENTED_REQUEST_SERVER,
|
TSM_STATE_SEGMENTED_REQUEST,
|
||||||
TSM_STATE_SEGMENTED_CONFIRMATION,
|
TSM_STATE_SEGMENTED_CONFIRMATION
|
||||||
TSM_STATE_SEGMENTED_RESPONSE_SERVER
|
|
||||||
} BACNET_TSM_STATE;
|
} 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 */
|
/* 5.4.1 Variables And Parameters */
|
||||||
/* The following variables are defined for each instance of */
|
/* The following variables are defined for each instance of */
|
||||||
/* Transaction State Machine: */
|
/* Transaction State Machine: */
|
||||||
typedef struct BACnet_TSM_Data {
|
typedef struct BACnet_TSM_Data {
|
||||||
/* used to count APDU retries */
|
/* used to count APDU retries */
|
||||||
uint8_t RetryCount;
|
uint8_t RetryCount;
|
||||||
#if BACNET_SEGMENTATION_ENABLED
|
|
||||||
/* used to count segment retries */
|
/* used to count segment retries */
|
||||||
uint8_t SegmentRetryCount;
|
/*uint8_t SegmentRetryCount; */
|
||||||
/* used to control APDU retries and the acceptance of server replies */
|
/* 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 */
|
/* 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 */
|
/* stores the sequence number of the first segment of */
|
||||||
/* a sequence of segments that fill a window */
|
/* a sequence of segments that fill a window */
|
||||||
uint8_t InitialSequenceNumber;
|
/*uint8_t InitialSequenceNumber; */
|
||||||
/* stores the current window size */
|
/* stores the current window size */
|
||||||
uint8_t ActualWindowSize;
|
/*uint8_t ActualWindowSize; */
|
||||||
/* stores the window size proposed by the segment sender */
|
/* stores the window size proposed by the segment sender */
|
||||||
uint8_t ProposedWindowSize;
|
/*uint8_t ProposedWindowSize; */
|
||||||
/* used to perform timeout on PDU segments */
|
/* used to perform timeout on PDU segments */
|
||||||
uint16_t SegmentTimer;
|
/*uint8_t SegmentTimer; */
|
||||||
#endif
|
|
||||||
/* used to perform timeout on Confirmed Requests */
|
/* used to perform timeout on Confirmed Requests */
|
||||||
/* in milliseconds */
|
/* in milliseconds */
|
||||||
uint16_t RequestTimer;
|
uint16_t RequestTimer;
|
||||||
@@ -92,28 +73,9 @@ typedef struct BACnet_TSM_Data {
|
|||||||
BACNET_ADDRESS dest;
|
BACNET_ADDRESS dest;
|
||||||
/* the network layer info */
|
/* the network layer info */
|
||||||
BACNET_NPDU_DATA npdu_data;
|
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 */
|
/* copy of the APDU, should we need to send it again */
|
||||||
uint8_t apdu[MAX_PDU];
|
uint8_t apdu[MAX_PDU];
|
||||||
#endif
|
unsigned apdu_len;
|
||||||
} BACNET_TSM_DATA;
|
} BACNET_TSM_DATA;
|
||||||
|
|
||||||
typedef void (*tsm_timeout_function)(uint8_t invoke_id);
|
typedef void (*tsm_timeout_function)(uint8_t invoke_id);
|
||||||
@@ -161,59 +123,6 @@ bool tsm_invoke_id_free(uint8_t invokeID);
|
|||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
bool tsm_invoke_id_failed(uint8_t invokeID);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@@ -164,11 +164,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#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 */
|
/* for confirmed messages, this is the number of transactions */
|
||||||
/* that we hold in a queue waiting for timeout. */
|
/* that we hold in a queue waiting for timeout. */
|
||||||
/* Configure to zero if you don't want any confirmed messages */
|
/* 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