BACnet – путь к интеграции систем безопасности в общую систему управления зданием. Часть 6


Скачать

Сергей ЛЁВИН,

главный конструктор СИГМА–ИС

les@sigma-is.ru

Протокол BACnet Data Unit

В этой статье рассматривается основной протокол передачи данных BACnet. Прикладной уровень этого протокола (APDU – Application Layer Protocol Data Units) используется в BACnet для передачи информации, содержащейся в службах приложений и их параметрах.

Стандарт ISO 8824, спецификация нотации абстрактного синтаксиса ASN.1, был выбран как метод для представления данных в службах BACnet. ASN.1 предоставляет абстрактный синтаксис. Тем не менее, точный побитовый формат APDU может иметь несколько форм, в зависимости от выбранных правил кодирования или представления данных в пакете. Внутри модели OSI (модель взаимодействия открытых систем) правила формирования данных для передачи выбираются на уровне представления. Причем определяются не только базовые правила кодирования данных, но также и будут ли данные подвергаться дополнительным манипуляциям, таким как компрессия, шифрование и т.д. Так как BACnet использует упрощенную модель OSI, которая не предоставляет никакой функциональности уровня представления, правила формирования ADPU должны быть определены самими коммуникационными устройствами. Правила кодирования данных в BACnet были разработаны в соответствии с требованиями систем автоматизации и управления зданиями к простоте и компактности. В принципе, службы и процедуры BACnet могут быть использованы в будущем в полностью в OSI-совместимой сети путем добавления поддержки уровня представления.

Кодирование согласно ASN.1, определенное в ISO 8825 (спецификация базовых правил кодирования) применяется ко всем элементам пакета PDU. Каждый элемент данных представляется тремя компонентами: идентификатор, длина, и собственно данные. Явная идентификация каждого элемента данных позволяет разрабатывать парсеры, которые могут декодировать любой пакет без знания формата или семантики контента. Альтернатива явному описанию каждого элемента данных является общее соглашение о формате и размещении данных внутри пакета. Первый подход более общий, но и более затратный, второй – более эффективный по затратам, но и более строгий в реализации. Вариант выбранный в BACnet является компромиссным. Фиксированные части пакета содержат управляющие данные протокола и их формат подразумевается, что известен, то есть в самом пакете данных о формате не содержится. Переменная часть пакета содержит контекстно-зависимую информацию и явно описана в PDU. В результате значительно снижаются затраты на описание предопределенных данных и в то же время имеется возможность добавления данных новых служб в пакет.

Фиксированная часть пакета APDU

BACnet APDU содержит управляющую информацию протокола и также некоторые пользовательские данные. Блок PCI (Protocol Control Information) содержит данные, необходимые для работы протокола прикладного уровня и включает в себя тип APDU, информацию в соответствии с запросами и ответами служб, данные для сборки сегментированных сообщений. Эта информация содержится в заголовке пакета, фиксированной части APDU. Пользовательские данные содержат информацию, специфичную для индивидуальных запросов и ответов служб и относятся к переменной части APDU. Так как каждый пакет APDU содержит поля PCI, BACnet упаковывает эти данные без использования тегов или длины данных, несмотря на то, что ASN.1 формально требует наличие тегов в синтаксическом описании всех полей. Теги используются для описания переменного контента пользовательских данных. Таким выборочным использованием тегов достигается уменьшение размера пакета.

В качестве примера рассмотрим формат заголовка пакета запроса с подтверждением.

BACnet-Confirmed-Request-PDU ::= SEQUENCE {

            pdu-type                                           [0] Unsigned(0..15) – 0 для этого типа PDU

            segmented-message                                 [1] BOOLEAN

            more-follows                                               [2] BOOLEAN

            segment-response-accepted                    [3] BOOLEAN

            reserved                                           [4] Unsigned (0..3) ­­– должно быть равно 0

            max-segment-accepted                 [5] Unsigned (0..7)

            max-APDU-length-accepted                    [6] Unsigned (0..15)

            invokeID                                           [7] Unsigned (0..255)

            sequence-number                         [8] Unsigned (0..255) – только если сообщение

сегментировано

            proposed-window-size                  [9] Unsigned (0..127) – только если сообщение

сегментировано

            service-choice                                             [10] BACnetConfirmedServiceChoice

            service-request                               [11] BACnetConfirmedServiceRequest

}

Описание полей заголовка

Поле

Описание

pdu-type 

Тип пакета

segmented-message

Этот параметр указывает, содержится ли запрос полностью в этом пакете, или только часть запроса. Если запрос представлен полностью, значение устанавливается равным FALSE. Если данный пакет содержит только фрагмент запроса, параметр будет равен TRUE.

more-follows

Этот параметр имеет значение, только если segmented-message = TRUE. В этом случае данный параметр устанавливается в TRUE для всех сегментов данного запроса, за исключением последнего и равен FALSE для финального сегмента запроса. Если segmented-message = FALSE, тогда more-follows устанавливается энкодером пакетов в FALSE и игнорируется декодером.

segmented-response-accepted

Этот параметр равен TRUE, если устройство формирующее запрос готово принять сегментированное составное сообщение в качестве ответа, иначе устанавливается значение FALSE. Считав значение этого параметра, отвечающее устройство может определить как формировать ответ.

max-segment-accepted

Этот опциональный параметр определяет максимальное количество сегментов, которое устройство может принять.

max-APDU-length-accepted

Параметр определяет максимальный размер одного пакета, который устройство может принять.

invokeID

Этот параметр может принимать целые значения в диапазоне 0 ­­– 255. Используется для связывания ответа с запросом. Параметр формируется устройством, выполняющим запрос. Значение должно быть уникальным для всех исходящих запросов от данного устройства. Одно и тоже значение должно быть во всех сегментах составного запроса. Когда invokeID связывается с пакетом, это значение задействуется в устройстве, пока не будет получен ответ с тем же значением invokeID, либо пока не наступит таймаут ожидания ответа. После этого данное значение освобождается для повторного использования.

sequence-number

Опциональный параметр, который используется только в сегментированных сообщениях. В этом случае, sequence-number последовательно инкрементируемое целое значение по модулю 256, которое идентифицирует каждый сегмент в составном запросе. Значение используется отвечающим устройством для подтверждения приема одного или более сегментов запроса. Значение параметра для первого сегмента составного запроса должно быть равно 0.

proposed-window-size

Опциональный параметр, который используется только в сегментированных сообщениях. В этом случае параметр обозначает  значение максимального количества сегментов, которые отправитель способен и может послать.

service-choice

Этот параметр значение службы BACnetConfirmedServiceChoice (будет описано позднее).

service-request

Дополнительные сервисные параметры.

В ответ принимающее устройство может сформировать два типа сообщения: простое подтверждение приема запроса BACnet-SimpleACK-PDU, если кроме подтверждения никаких данных отправлять не нужно. Или BACnet-ComplexACK-PDU, если в ответ передаются какие-либо данные.

Структура простого ответа:

BACnet-SimpleACK-PDU ::= SEQUENCE {

            pdu-type                                           [0] Unsigned(0..15) – 2 для этого типа PDU

            reserved                                           [1] Unsigned (0..15) ­­– должно быть равно 0

            original-invokeID                            [2] Unsigned (0..255)

            service-ACK-choice                                   [3] BACnetConfirmedServiceChoice

}

Описание полей заголовка

Поле

Описание

pdu-type

Тип пакета

original-invokeID

Содержит значение invokeID, полученное в запросе.

service-choice

также повторяет значение соответствующего поля запроса.

Структура ответа с дополнительными данными

BACnet-ComplexACK-PDU ::= SEQUENCE {

            pdu-type                                           [0] Unsigned(0..15) – 3 для этого типа PDU

            segmented-message                                 [1] BOOLEAN

            more-follows                                               [2] BOOLEAN

            reserved                                           [3] Unsigned (0..3) ­­– должно быть равно 0

            original-invokeID                            [4] Unsigned (0..255)

            sequence-number                         [5] Unsigned (0..255) – только если сообщение

сегментировано

            proposed-window-size                  [6] Unsigned (0..127) – только если сообщение

сегментировано

            service-ACK-choice                                   [7] BACnetConfirmedServiceChoice

            service-ACK                                    [8] BACnet-Confirmed-Service-ACK

}

Описание полей заголовка

Поле

Описание

pdu-type

Тип пакета

segmented-message

Этот параметр указывает, содержится ли ответ полностью в этом пакете, или только часть ответа. Если ответ представлен полностью, значение устанавливается равным FALSE. Если данный пакет содержит только фрагмент ответа, параметр будет равен TRUE.

more-follows

Этот параметр имеет значение, только если segmented-message = TRUE. В этом случае данный параметр устанавливается в TRUE для всех сегментов данного ответа, за исключением последнего и равен FALSE для финального сегмента ответа. Если segmented-message = FALSE, тогда more-follows устанавливается энкодером пакетов в FALSE и игнорируется декодером.

original-invokeID

Содержит значение invokeID, полученное в запросе. Одно и тоже значение должно быть во всех сегментах составного ответа.

sequence-number

Опциональный параметр, который используется только в сегментированных сообщениях. В этом случае, sequence-number последовательно инкрементируемое целое значение по модулю 256, которое идентифицирует каждый сегмент в составном ответе. Значение используется запрашивающим устройством для подтверждения приема одного или более сегментов ответа. Значение параметра для первого сегмента составного ответа должно быть равно 0.

proposed-window-size

Опциональный параметр, который используется только в сегментированных сообщениях. В этом случае параметр обозначает  значение максимального количества сегментов, которые могут быть в ответе.

service-ACK-choice

Этот параметр значение службы BACnetConfirmedServiceChoice (будет описано позднее).

service-ACK

Дополнительные сервисные параметры.

Когда принимающее устройство принимает сегмент составного запроса, то на каждый принятый сегмент формируется подтверждение BACnet-SegmentACK-PDU. Это сообщение также служит запросом на принятие следующего сегмента.

BACnet-SegmentACK-PDU ::= SEQUENCE {

            pdu-type                                           [0] Unsigned(0..15) – 4 для этого типа PDU

            reserved                                           [1] Unsigned (0..3) ­­– должно быть равно 0

            negative-ACK                                             [2] BOOLEAN

            server                                                [3] BOOLEAN

            original-invokeID                            [4] Unsigned (0..255)

            sequence-number                         [5] Unsigned (0..255)

            actual-window-size                         [6] Unsigned (0..127)

}

Описание полей заголовка

Поле

Описание

pdu-type

Тип пакета

negative-ack

Этот параметр устанавливается в TRUE, если сегмент принят в неправильном порядке, то есть имеются пропущенные сегменты. Иначе значение будет FALSE.

server

Этот параметр устанавливается в TRUE, если подтверждение отправляется сервером. То есть это подтверждение приема сегмента составного ответа.

original-invokeID

Содержит значение invokeID, полученное в запросе.

sequence-number

Этот параметр содержит значение sequence-number, принятое в предыдущем сегменте.

actual-window-size

Определяет количество сегментов сообщения, содержащих original-invokeID, которые отправитель будет принимать перед отправкой другого SegmentACK.

service-ACK-choice

Этот параметр значение службы BACnetConfirmedServiceChoice (будет описано позднее).

service-ACK

Дополнительные сервисные параметры.

В случае каких-либо ошибок при разборе принятого пакета устройство отправляет уведомление об ошибке BACnet-Error-PDU.

BACnet-Error-PDU ::= SEQUENCE {

            pdu-type                                           [0] Unsigned (0..15) – 5 для этого типа PDU

            reserved                                           [1] Unsigned (0..15) ­­– должно быть равно 0

            original-invokeID                            [2] Unsigned (0..255)

            error-choice                                     [3] BACnetConfirmedServiceChoice

            error                                                   [4] BACnet-Error

}

Описание полей заголовка

Поле

Описание

pdu-type

Тип пакета

original-invokeID

Содержит значение invokeID, полученное в запросе.

error-choice

Содержит значение тег значения BACnet-Error

error

Содержит код ошибки

Устройство также может отклонить принятое сообщение в случае каких-либо синтаксических ошибок или других ошибок протокола. Только сообщения с подтверждением могут быть отклонены.

BACnet-Reject-PDU ::= SEQUENCE {

            pdu-type                                           [0] Unsigned (0..15) – 6 для этого типа PDU

            reserved                                           [1] Unsigned (0..15) ­­– должно быть равно 0

            original-invokeID                            [2] Unsigned (0..255)

            reject-reason                                               [3] BACnetRejectReason

}

Описание полей заголовка

Поле

Описание

pdu-type

Тип пакета

original-invokeID

Содержит значение invokeID, полученное в запросе.

reject-reason

Содержит причину отклонения сообщения.

Для прерывания передачи текущего сообщения служит команда BACnet-Abort-PDU.

BACnet-Abort-PDU ::= SEQUENCE {

            pdu-type                                           [0] Unsigned (0..15) – 7 для этого типа PDU

            reserved                                           [1] Unsigned (0..15) ­­– должно быть равно 0

            server                                                [2] BOOLEAN

            original-invokeID                            [3] Unsigned (0..255)

            abort-reason                                    [4] BACnetAbortReason

}

Описание полей заголовка

Поле

Описание

pdu-type

Тип пакета

server

Этот параметр устанавливается в TRUE, если это сообщение отправляется сервером.

original-invokeID

Содержит значение invokeID, полученное в запросе.

break-reason

Содержит причину прекращения передачи сообщения.


Переменная часть пакета APDU

Мы рассмотрели формат фиксированного заголовка пакета. Теперь вкратце о полезной нагрузке сообщения (BACnetConfirmedServiceChoice) или сервисных параметрах. Все элементы данных параметров называются тегами. Каждый тег обозначает уникальный параметр или подпараметр. BACnet использует два класса тегов. Первый определяет фундаментальный тип данных используемых и определенных в BACnet, такие как BOOLEAN, Unsigned, CharacterString, Date, Time или BACnetObjectIdentifier. Второй  класс тегов используется для идентификации элементов данных, которые могут зависеть от контекста, в котором они используются. Такие теги называются контекстно-зависимыми. В некоторых случаях тип данных параметра не может быть ясен из контекста, где он используется. Тогда может потребоваться применение и контекстно-зависимых и предопределенных тегов. В этой ситуации по спецификации ASN.1 используются так называемые сервисные параметры, в которых типы данных индицируются ключевыми словами ABSTRACT-SYNTAX, CHOICE, SEQUENCE или SEQUENCE OF.

Теги BACnet описываются начальным байтом и, возможно, дополнительными последующими байтами. Начальный байт или октет определен следующим образом:

Начальный октет тега

Биты

Поле

Описание

7-4

Номер тега

Номер тега внутри класса

3

Класс

Класс тега (зависит от приложения или контекста). 0 – для предопределенных тегов, 1 – для контекстно-зависимых тегов.

2-0

Длина/значение/тип

В зависимости от данных тега определяет длину, значение или тип данных.

В следующих байтах тега помещаются непосредственно данные, специфичные для класса и типа тега. Таким образом, в BACnet предоставляется возможность определить и передать в стандартном сообщении данные практически любого типа.

                                                                                                                    Продолжение следует.

 

Источник: Журнал Алгоритм безопасности №6, 2012

Архив публикаций