BACnet WHO-IS服务协议栈代码分析(2) ------ whois_decode_service_request(....)函数

来源:互联网 发布:威瑞森数据泄露报告 编辑:程序博客网 时间:2024/06/06 09:51

在有了第一篇分析之后,whois_decode_service_request这个函数理解起来就简单很多了。

<strong>1 、int whois_decode_service_request(2 、   uint8_t * apdu,3 、   unsigned apdu_len,4 、   int32_t * pLow_limit,5 、   int32_t * pHigh_limit)6 、{7 、   int len = 0;8 、   uint8_t tag_number = 0;9 、   uint32_t len_value = 0;10、    uint32_t decoded_value = 0;11、12、    /* optional limits - must be used as a pair */13、    if (apdu_len) {14、        len +=15、            decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);16、        if (tag_number != 0) {17、            return BACNET_STATUS_ERROR;18、        }19、        if (apdu_len > len) {20、            len += decode_unsigned(&apdu[len], len_value, &decoded_value);21、            if (decoded_value <= BACNET_MAX_INSTANCE) {22、               if (pLow_limit) {23、                    *pLow_limit = decoded_value;24、                }25、            }26、            if (apdu_len > len) {27、                len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);28、                if (tag_number != 1) {29、                    return BACNET_STATUS_ERROR;30、                }31、                if (apdu_len > len) {32、                    len += decode_unsigned(&apdu[len], len_value, &decoded_value);33、                    if (decoded_value <= BACNET_MAX_INSTANCE) {34、                        if (pHigh_limit) {35、                            *pHigh_limit = decoded_value;36、                        }37、                    }38、                } else {39、                    return BACNET_STATUS_ERROR;40、                }41、            } else {42、                return BACNET_STATUS_ERROR;43、            }44、        } else {45、            return BACNET_STATUS_ERROR;46、        }47、    } else {48、        if (pLow_limit) {49、            *pLow_limit = -1;50、        }51、        if (pHigh_limit) {52、            *pHigh_limit = -1;53、        }54、        len = 0;55、    }56、57、    return len;58、}</strong>

        首先,来看看len的值是怎样得到的。首先通过调用decode_tag_number_and_value(...),在这个函数里,先调用了decode_tag_number(...)。

<strong>int decode_tag_number(    uint8_t * apdu,    uint8_t * tag_number){    int len = 1;        /* return value */    /* decode the tag number first */    if (IS_EXTENDED_TAG_NUMBER(apdu[0])) {        /* extended tag */        if (tag_number) {            *tag_number = apdu[1];        }        len++;    } else {        if (tag_number) {            *tag_number = (uint8_t) (apdu[0] >> 4);        }    }    return len;}</strong>

       这个函数主要用于判断这个编码的标记号编码是否存在扩展标记,如果是扩展标记,则返回2个字节长度,不是扩展标记则返回1个字节长度。在获得了标记的字节长度之后。回到decode_tag_number_and_value(...):

<strong>1、int decode_tag_number_and_value(2、  uint8_t * apdu,3、  uint8_t * tag_number,4、   uint32_t * value)5、{6、    int len = 1;7、    uint16_t value16;8、    uint32_t value32;9、10、    len = decode_tag_number(&apdu[0], tag_number);11、    if (IS_EXTENDED_VALUE(apdu[0])) {12、        /* tagged as uint32_t */13、        if (apdu[len] == 255) {14、            len++;15、            len += decode_unsigned32(&apdu[len], &value32);16、            if (value) {17、                *value = value32;18、            }19、        }20、        /* tagged as uint16_t */21、        else if (apdu[len] == 254) {22、            len++;23、            len += decode_unsigned16(&apdu[len], &value16);24、            if (value) {25、                *value = value16;26、            }27、        }28、        /* no tag - must be uint8_t */29、        else {30、            if (value) {31、                *value = apdu[len];32、            }33、            len++;34、        }35、    } else if (IS_OPENING_TAG(apdu[0]) && value) {36、        *value = 0;37、    } else if (IS_CLOSING_TAG(apdu[0]) && value) {38、        /* closing tag */39、        *value = 0;40、    } else if (value) {41、        /* small value */42、        *value = apdu[0] & 0x07;43、    }44、45、    return len;46、}</strong>
       在得到了标记号的长度之后,就通过调用 IS_EXTENDED_VALUE 这个宏得到的值来判断其扩展值有没有被使用。这个是用于原语数据的判断,IS_EXTENDED_VALUE(x) ((x & 0x07) == 5) 。 在 20.2.1.3.1 小节中,定义了对于长度在大于5的字节,其主字节的长度/值/类型域被设置为B'101'。然后判断下一个字节,如果是存在扩展值得话,那么接下来这个字节存储的是D'254'或D'255'。当存储的是D'254'时,则表示该数据长度在[254, 65535]之间,并且其后要附加两个字节,因此,需要调用decode_unsigned16(...)来分配两个字节的空间,要注意的是,在decode_unsigned16(...)中,还存在一个大端转小端的过程。同理,可以得知当存储的是D'255'的时候的情况。

        在判断完是否有扩展值之后,需要判断这个编码是否为“构件”,“构件”元素是指编码的数据结构中包含有标记元素的,其中,标记元素包括"opening"和"closing"。如果是"opening"标记,那么长度/值/类型域将被设置为B‘110’,如果是"closing"标记,那么长度/值/类型域将被设置为B‘111’。最后,返回了的长度包括了tag和value的长度。回到who_is_decode_service_request(....)这个函数.

        比较此时apdu的长度与传入的参数apdu_len,如果比apdu_len要小,则说明需要设置设备阈值的范围。在16.9.1.1.1小节提到" 如果 '设备实例低阈值范围' 参数存在,则 ' 设备实例高阈值范围 ' 也必须存在 "。因此,在whois_decode_service_request(....)的21~25是先判断设备实例低阈值,26~43则是判断设备实例高阈值。由于设备低阈值与设备高阈值是成对出现的缘故,因此,当没有设置这两个阈值的值的时候,将其值设置为-1并且返回0个字节。

        

0 0