在有了第一篇分析之后,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个字节。