/** * @file * @brief BACnet ReinitializeDevice-Request encode and decode helper functions * @author Steve Karg * @date 2005 * @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 */ #include /* BACnet Stack defines - first */ #include "bacnet/bacdef.h" /* BACnet Stack API */ #include "bacnet/bacdcode.h" #include "bacnet/rd.h" #if BACNET_SVC_RD_A /** * @brief Encode ReinitializeDevice-Request APDU * * ReinitializeDevice-Request ::= SEQUENCE { * reinitialized-state-of-device [0] ENUMERATED { * coldstart (0), * warmstart (1), * start-backup (2), * end-backup (3), * start-restore (4), * end-restore (5), * abort-restore (6), * activate-changes (7) * }, * password [1] CharacterString (SIZE (1..20)) OPTIONAL * } * * @param apdu Pointer to the buffer, or NULL for length * @param state Reinitialization state * @param password Pointer to the pass phrase. * @return number of bytes encoded */ int reinitialize_device_encode( uint8_t *apdu, BACNET_REINITIALIZED_STATE state, const BACNET_CHARACTER_STRING *password) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ size_t length; /* reinitialized-state-of-device [0] ENUMERATED */ len = encode_context_enumerated(apdu, 0, state); apdu_len += len; if (apdu) { apdu += len; } /* password [1] CharacterString (SIZE (1..20)) OPTIONAL */ if (password) { if (characterstring_encoding(password) == CHARACTER_UTF8) { /* UTF-8 code points can be up to 4 bytes long */ length = characterstring_utf8_length(password); } else { length = characterstring_length(password); } if ((length >= 1) && (length <= 20)) { len = encode_context_character_string(apdu, 1, password); apdu_len += len; } } return apdu_len; } /** * @brief Encode the ReinitializeDevice-Request service * @param apdu Pointer to the buffer for encoding into * @param apdu_size number of bytes available in the buffer * @param state Reinitialization state * @param password Pointer to the pass phrase. * @return number of bytes encoded, or zero if unable to encode or too large */ size_t reinitialize_device_request_encode( uint8_t *apdu, size_t apdu_size, BACNET_REINITIALIZED_STATE state, const BACNET_CHARACTER_STRING *password) { size_t apdu_len = 0; /* total length of the apdu, return value */ apdu_len = reinitialize_device_encode(NULL, state, password); if (apdu_len > apdu_size) { apdu_len = 0; } else { apdu_len = reinitialize_device_encode(apdu, state, password); } return apdu_len; } /** * @brief Encode Reinitialize Device service * @param apdu Pointer to the APDU buffer. * @param invoke_id Invoke-Id * @param state Reinitialization state * @param password Pointer to the pass phrase. * * @return Bytes encoded. */ int rd_encode_apdu( uint8_t *apdu, uint8_t invoke_id, BACNET_REINITIALIZED_STATE state, const BACNET_CHARACTER_STRING *password) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ if (apdu) { apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_REINITIALIZE_DEVICE; } len = 4; apdu_len += len; if (apdu) { apdu += len; } len = reinitialize_device_encode(apdu, state, password); apdu_len += len; return apdu_len; } #endif /** * @brief Decode Reinitialize Device service * * ReinitializeDevice-Request ::= SEQUENCE { * reinitialized-state-of-device [0] ENUMERATED { * coldstart (0), * warmstart (1), * start-backup (2), * end-backup (3), * start-restore (4), * end-restore (5), * abort-restore (6), * activate-changes (7) * }, * password [1] CharacterString (SIZE (1..20)) OPTIONAL * } * * @param apdu Pointer to the APDU buffer. * @param apdu_size Valid bytes in the buffer * @param state Pointer to the Reinitialization state * @param password Pointer to the pass phrase. * * @return number of bytes decoded, or #BACNET_STATUS_ERROR if malformed */ int rd_decode_service_request( const uint8_t *apdu, unsigned apdu_size, BACNET_REINITIALIZED_STATE *state, BACNET_CHARACTER_STRING *password) { int len = 0, apdu_len = 0; uint32_t value = 0; /* check for value pointers */ if (apdu) { /* Tag 0: reinitializedStateOfDevice */ len = bacnet_enumerated_context_decode( &apdu[apdu_len], apdu_size - apdu_len, 0, &value); if (len > 0) { if (state) { *state = (BACNET_REINITIALIZED_STATE)value; } apdu_len = len; } else { apdu_len = BACNET_STATUS_ERROR; } /* Tag 1: password - optional */ if (apdu_len < apdu_size) { len = bacnet_character_string_context_decode( &apdu[apdu_len], apdu_size - apdu_len, 1, password); if (len > 0) { apdu_len += len; } else { apdu_len = BACNET_STATUS_ERROR; } } else { characterstring_init_ansi(password, ""); } } return apdu_len; }