Feature/safe decode npdu (#84)

* Added safe version to decode npdu

* Calling safe decoder function.

* Added comments and apdu_len checks.

* Fixed signed/unsigned warnings.
This commit is contained in:
Roy Schneider
2020-05-11 15:30:18 +02:00
committed by GitHub
parent ec923e51a3
commit 094ac1db00
5 changed files with 170 additions and 77 deletions
+17 -2
View File
@@ -54,6 +54,14 @@
#define snprintf _snprintf
#endif
/** @brief Encode application data given by a pointer into the APDU.
* Return the number encoded bytes.
*
* @param apdu Pointer to the buffer to encode to.
* @param value Pointer to the application data.
*
* @return Bytes encoded.
*/
int bacapp_encode_application_data(
uint8_t *apdu, BACNET_APPLICATION_DATA_VALUE *value)
{
@@ -395,8 +403,15 @@ bool bacapp_decode_application_data_safe(uint8_t *new_apdu,
return ret;
}
/* Decode the data and
return the number of octets consumed. */
/** @brief Decode the data and
* return the number of octets consumed.
*
* @param apdu Pointer to the received data.
* @param tag_data_type Data type to be decoded.
* @param len_value_type Length of the data in bytes.
*
* @return Count of bytes decoded.
*/
int bacapp_decode_data_len(
uint8_t *apdu, uint8_t tag_data_type, uint32_t len_value_type)
{
+1 -1
View File
@@ -76,7 +76,7 @@ void npdu_handler(BACNET_ADDRESS *src, /* source address */
/* only handle the version that we know how to handle */
if (pdu[0] == BACNET_PROTOCOL_VERSION) {
apdu_offset = npdu_decode(&pdu[0], &dest, src, &npdu_data);
apdu_offset = bacnet_npdu_decode(&pdu[0], pdu_len, &dest, src, &npdu_data);
if (npdu_data.network_layer_message) {
/*FIXME: network layer message received! Handle it! */
#if PRINT_ENABLED
+87 -41
View File
@@ -286,6 +286,7 @@ void npdu_encode_npdu_data(BACNET_NPDU_DATA *npdu_data,
}
}
/** Decode the NPDU portion of a received message, particularly the NCPI byte.
* The Network Layer Protocol Control Information byte is described
* in section 6.2.2 of the BACnet standard.
@@ -302,6 +303,38 @@ void npdu_encode_npdu_data(BACNET_NPDU_DATA *npdu_data,
* This src describes the original source of the message when
* it had to be routed to reach this BACnet Device.
* @param npdu_data [out] Returns a filled-out structure with information
* decoded from the NCPI and other NPDU
* bytes.
* @return On success, returns the number of bytes which were decoded from the
* NPDU section; if this is a network layer message, there may
* be more bytes left in the NPDU; if not a network msg, the APDU follows. If 0
* or negative, there were problems with the data or arguments.
*/
int npdu_decode(uint8_t *npdu,
BACNET_ADDRESS *dest,
BACNET_ADDRESS *src,
BACNET_NPDU_DATA *npdu_data)
{
return bacnet_npdu_decode(npdu, MAX_NPDU, dest, src, npdu_data);
}
/** Decode the NPDU portion of a received message, particularly the NCPI byte.
* The Network Layer Protocol Control Information byte is described
* in section 6.2.2 of the BACnet standard.
* @param npdu [in] Buffer holding the received NPDU header bytes (must be at
* least 2)
* @param pdu_len [in] Length of the received data to prevent overruns.
* @param dest [out] Returned with routing destination information if the NPDU
* has any and if this points to non-null storage for it.
* If dest->net and dest->len are 0 on return, there is no
* routing destination information.
* @param src [out] Returned with routing source information if the NPDU
* has any and if this points to non-null storage for it.
* If src->net and src->len are 0 on return, there is no
* routing source information.
* This src describes the original source of the message when
* it had to be routed to reach this BACnet Device.
* @param npdu_data [out] Returns a filled-out structure with information
* decoded from the NCPI and other NPDU
* bytes.
* @return On success, returns the number of bytes which were decoded from the
@@ -309,7 +342,8 @@ void npdu_encode_npdu_data(BACNET_NPDU_DATA *npdu_data,
* be more bytes left in the NPDU; if not a network msg, the APDU follows. If 0
* or negative, there were problems with the data or arguments.
*/
int npdu_decode(uint8_t *npdu,
int bacnet_npdu_decode(uint8_t *npdu,
uint16_t pdu_len,
BACNET_ADDRESS *dest,
BACNET_ADDRESS *src,
BACNET_NPDU_DATA *npdu_data)
@@ -322,7 +356,7 @@ int npdu_decode(uint8_t *npdu,
uint8_t dlen = 0;
uint8_t mac_octet = 0;
if (npdu && npdu_data) {
if (npdu && npdu_data && (pdu_len >= 2)) {
/* Protocol Version */
npdu_data->protocol_version = npdu[0];
/* control octet */
@@ -356,24 +390,26 @@ int npdu_decode(uint8_t *npdu,
/* DLEN = 0 denotes broadcast MAC DADR and DADR field is absent */
/* DLEN > 0 specifies length of DADR field */
if (npdu[1] & BIT(5)) {
len += decode_unsigned16(&npdu[len], &dest_net);
/* DLEN = 0 denotes broadcast MAC DADR and DADR field is absent */
/* DLEN > 0 specifies length of DADR field */
dlen = npdu[len++];
if (dest) {
dest->net = dest_net;
dest->len = dlen;
}
if (dlen) {
if (dlen > MAX_MAC_LEN) {
/* address is too large could be a malformed message */
return -1;
if (pdu_len >= (len + 3)) {
len += decode_unsigned16(&npdu[len], &dest_net);
/* DLEN = 0 denotes broadcast MAC DADR and DADR field is absent */
/* DLEN > 0 specifies length of DADR field */
dlen = npdu[len++];
if (dest) {
dest->net = dest_net;
dest->len = dlen;
}
if (dlen) {
if ((dlen > MAX_MAC_LEN) || (pdu_len < (len + dlen))) {
/* address is too large could be a malformed message */
return -1;
}
for (i = 0; i < dlen; i++) {
mac_octet = npdu[len++];
if (dest) {
dest->adr[i] = mac_octet;
for (i = 0; i < dlen; i++) {
mac_octet = npdu[len++];
if (dest) {
dest->adr[i] = mac_octet;
}
}
}
}
@@ -390,24 +426,26 @@ int npdu_decode(uint8_t *npdu,
/* 0 = SNET, SLEN, and SADR absent */
/* 1 = SNET, SLEN, and SADR present */
if (npdu[1] & BIT(3)) {
len += decode_unsigned16(&npdu[len], &src_net);
/* SLEN = 0 denotes broadcast MAC SADR and SADR field is absent */
/* SLEN > 0 specifies length of SADR field */
slen = npdu[len++];
if (src) {
src->net = src_net;
src->len = slen;
}
if (slen) {
if (slen > MAX_MAC_LEN) {
/* address is too large could be a malformed message */
return -1;
if (pdu_len >= (len + 3)) {
len += decode_unsigned16(&npdu[len], &src_net);
/* SLEN = 0 denotes broadcast MAC SADR and SADR field is absent */
/* SLEN > 0 specifies length of SADR field */
slen = npdu[len++];
if (src) {
src->net = src_net;
src->len = slen;
}
if (slen) {
if ((slen > MAX_MAC_LEN) || (pdu_len < (len + slen))) {
/* address is too large could be a malformed message */
return -1;
}
for (i = 0; i < slen; i++) {
mac_octet = npdu[len++];
if (src) {
src->adr[i] = mac_octet;
for (i = 0; i < slen; i++) {
mac_octet = npdu[len++];
if (src) {
src->adr[i] = mac_octet;
}
}
}
}
@@ -428,19 +466,27 @@ int npdu_decode(uint8_t *npdu,
/* destined for a remote network, i.e., if DNET is present. */
/* This is a one-octet field that is initialized to a value of 0xff. */
if (dest_net) {
npdu_data->hop_count = npdu[len++];
if (pdu_len > len) {
npdu_data->hop_count = npdu[len++];
} else {
npdu_data->hop_count = 0;
}
} else {
npdu_data->hop_count = 0;
}
/* Indicates that the NSDU conveys a network layer message. */
/* Message Type field is present. */
if (npdu_data->network_layer_message) {
npdu_data->network_message_type =
(BACNET_NETWORK_MESSAGE_TYPE)npdu[len++];
/* Message Type field contains a value in the range 0x80 - 0xFF, */
/* then a Vendor ID field shall be present */
if (npdu_data->network_message_type >= 0x80) {
len += decode_unsigned16(&npdu[len], &npdu_data->vendor_id);
if (pdu_len > len) {
npdu_data->network_message_type =
(BACNET_NETWORK_MESSAGE_TYPE)npdu[len++];
/* Message Type field contains a value in the range 0x80 - 0xFF, */
/* then a Vendor ID field shall be present */
if (npdu_data->network_message_type >= 0x80) {
if (pdu_len >= (len + 2)) {
len += decode_unsigned16(&npdu[len], &npdu_data->vendor_id);
}
}
}
} else {
/* Since npdu_data->network_layer_message is false,
+8
View File
@@ -95,6 +95,14 @@ extern "C" {
BACNET_ADDRESS * src,
BACNET_NPDU_DATA * npdu_data);
BACNET_STACK_EXPORT
int bacnet_npdu_decode(
uint8_t * npdu,
uint16_t pdu_len,
BACNET_ADDRESS * dest,
BACNET_ADDRESS * src,
BACNET_NPDU_DATA * npdu_data);
#ifdef __cplusplus
}
#endif /* __cplusplus */
+57 -33
View File
@@ -39,8 +39,12 @@
/** @file whohas.c Encode/Decode Who-Has requests */
/* encode service - use -1 for limit for unlimited */
/** Encode Who-Hasservice - use -1 for limit for unlimited
*
* @param apdu Pointer to the APDU.
* @param data Pointer to the Who-Has application data.
*
* @return Bytes encoded. */
int whohas_encode_apdu(uint8_t *apdu, BACNET_WHO_HAS_DATA *data)
{
int len = 0; /* length of each encoding */
@@ -75,7 +79,13 @@ int whohas_encode_apdu(uint8_t *apdu, BACNET_WHO_HAS_DATA *data)
return apdu_len;
}
/* decode the service request only */
/** Decode the Who-Has service request only.
*
* @param apdu Pointer to the received data.
* @param apdu_len Bytes valid in the receive buffer.
* @param data Pointer to the application dta to be filled in.
*
* @return Bytes decoded. */
int whohas_decode_service_request(
uint8_t *apdu, unsigned apdu_len, BACNET_WHO_HAS_DATA *data)
{
@@ -90,42 +100,56 @@ int whohas_decode_service_request(
if (decode_is_context_tag(&apdu[len], 0)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
len += decode_unsigned(&apdu[len], len_value, &unsigned_value);
if (unsigned_value <= BACNET_MAX_INSTANCE) {
data->low_limit = unsigned_value;
}
if (!decode_is_context_tag(&apdu[len], 1)) {
return -1;
}
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
len += decode_unsigned(&apdu[len], len_value, &unsigned_value);
if (unsigned_value <= BACNET_MAX_INSTANCE) {
data->high_limit = unsigned_value;
if ((unsigned)len < apdu_len) {
len += decode_unsigned(&apdu[len], len_value, &unsigned_value);
if ((unsigned)len < apdu_len) {
if (unsigned_value <= BACNET_MAX_INSTANCE) {
data->low_limit = unsigned_value;
}
if (!decode_is_context_tag(&apdu[len], 1)) {
return -1;
}
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
if ((unsigned)len < apdu_len) {
len += decode_unsigned(&apdu[len], len_value, &unsigned_value);
if (unsigned_value <= BACNET_MAX_INSTANCE) {
data->high_limit = unsigned_value;
}
}
}
}
} else {
data->low_limit = -1;
data->high_limit = -1;
}
/* object id */
if (decode_is_context_tag(&apdu[len], 2)) {
data->is_object_name = false;
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
len += decode_object_id(
&apdu[len], &decoded_type, &data->object.identifier.instance);
data->object.identifier.type = decoded_type;
}
/* object name */
else if (decode_is_context_tag(&apdu[len], 3)) {
data->is_object_name = true;
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
len += decode_character_string(
&apdu[len], len_value, &data->object.name);
}
/* missing required parameters */
else {
if ((unsigned)len < apdu_len) {
if (decode_is_context_tag(&apdu[len], 2)) {
data->is_object_name = false;
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
if ((unsigned)len < apdu_len) {
len += decode_object_id(
&apdu[len], &decoded_type, &data->object.identifier.instance);
data->object.identifier.type = decoded_type;
}
}
/* object name */
else if (decode_is_context_tag(&apdu[len], 3)) {
data->is_object_name = true;
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
if ((unsigned)len < apdu_len) {
len += decode_character_string(
&apdu[len], len_value, &data->object.name);
}
} else {
/* missing required parameters */
return -1;
}
} else {
/* message too short */
return -1;
}
}