FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
bacnet-stack/src/bacnet/bacdcode.c at master · bacnet-stack/bacnet-stack · GitHub
Uh oh!
There was an error while loading.
Please reload this page
.
bacnet-stack
/
bacnet-stack
Public
Notifications
You must be signed in to change notification settings
Fork
298
Star
592
Code
Issues
90
Pull requests
2
Discussions
Actions
Security and quality
36
Insights
Additional navigation options
Code
Issues
Pull requests
Discussions
Actions
Security and quality
Insights
Expand file tree
Breadcrumbs
bacnet-stack
/
src
/
bacnet
/
bacdcode.c
Copy path
More file actions
More file actions
Latest commit
History
History
History
6319 lines (5814 loc) · 183 KB
Breadcrumbs
bacnet-stack
/
src
/
bacnet
/
bacdcode.c
Copy path
File metadata and controls
6319 lines (5814 loc) · 183 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* @file
* @brief BACnet primitive data encode and decode helper functions
* @author Steve Karg <skarg@users.sourceforge.net>
* @date 2004
* @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
*/
#include
<string.h>
/* BACnet Stack defines - first */
#include
"bacnet/bacdef.h"
/* BACnet Stack API */
#include
"bacnet/bacdcode.h"
#include
"bacnet/bacstr.h"
#include
"bacnet/bacint.h"
#include
"bacnet/bacreal.h"
#include
"bacnet/basic/sys/compare.h"
/* max-segments-accepted
B'000' Unspecified number of segments accepted.
B'001' 2 segments accepted.
B'010' 4 segments accepted.
B'011' 8 segments accepted.
B'100' 16 segments accepted.
B'101' 32 segments accepted.
B'110' 64 segments accepted.
B'111' Greater than 64 segments accepted.
*/
/* max-APDU-length-accepted
B'0000' Up to MinimumMessageSize (50 octets)
B'0001' Up to 128 octets
B'0010' Up to 206 octets (fits in a LonTalk frame)
B'0011' Up to 480 octets (fits in an ARCNET frame)
B'0100' Up to 1024 octets
B'0101' Up to 1476 octets (fits in an ISO 8802-3 frame)
B'0110' reserved by ASHRAE
B'0111' reserved by ASHRAE
B'1000' reserved by ASHRAE
B'1001' reserved by ASHRAE
B'1010' reserved by ASHRAE
B'1011' reserved by ASHRAE
B'1100' reserved by ASHRAE
B'1101' reserved by ASHRAE
B'1110' reserved by ASHRAE
B'1111' reserved by ASHRAE
*/
/* Encoding of BACNET Length/Value/Type tag
From clause 20.2.1.3.1
B'000' interpreted as Value = FALSE if application class == BOOLEAN
B'001' interpreted as Value = TRUE if application class == BOOLEAN
B'000' interpreted as Length = 0 if application class != BOOLEAN
B'001' interpreted as Length = 1
B'010' interpreted as Length = 2
B'011' interpreted as Length = 3
B'100' interpreted as Length = 4
B'101' interpreted as Length > 4
B'110' interpreted as Type = Opening Tag
B'111' interpreted as Type = Closing Tag
*/
/**
* Encode the max APDU value and return the encoded octed.
*
* @param max_segs from clause 20.1.2.4 max-segments-accepted
* @param max_apdu from clause 20.1.2.5 max-APDU-length-accepted
*
* @return The encoded octet
*/
uint8_t
encode_max_segs_max_apdu
(
int
max_segs
,
int
max_apdu
)
{
uint8_t
octet
=
0
;
if
(
max_segs
<
2
) {
octet
=
0
;
}
else
if
(
max_segs
<
4
) {
octet
=
0x10
;
}
else
if
(
max_segs
<
8
) {
octet
=
0x20
;
}
else
if
(
max_segs
<
16
) {
octet
=
0x30
;
}
else
if
(
max_segs
<
32
) {
octet
=
0x40
;
}
else
if
(
max_segs
<
64
) {
octet
=
0x50
;
}
else
if
(
max_segs
==
64
) {
octet
=
0x60
;
}
else
{
octet
=
0x70
;
}
/* max_apdu must be 50 octets minimum */
if
(
max_apdu
<=
50
) {
octet
|=
0x00
;
}
else
if
(
max_apdu
<=
128
) {
octet
|=
0x01
;
/*fits in a LonTalk frame */
}
else
if
(
max_apdu
<=
206
) {
octet
|=
0x02
;
/*fits in an ARCNET or MS/TP frame */
}
else
if
(
max_apdu
<=
480
) {
octet
|=
0x03
;
}
else
if
(
max_apdu
<=
1024
) {
octet
|=
0x04
;
/* fits in an ISO 8802-3 frame */
}
else
if
(
max_apdu
<=
1476
) {
octet
|=
0x05
;
}
return
octet
;
}
/**
* Decode the given octed into a maximum segments value.
*
* @param octed From clause 20.1.2.4 max-segments-accepted
* and clause 20.1.2.5 max-APDU-length-accepted
*
* @return Returns the maximum segments value.
*/
int
decode_max_segs
(
uint8_t
octet
)
{
int
max_segs
=
0
;
switch
(
octet
&
0xF0
) {
case
0
:
max_segs
=
0
;
break
;
case
0x10
:
max_segs
=
2
;
break
;
case
0x20
:
max_segs
=
4
;
break
;
case
0x30
:
max_segs
=
8
;
break
;
case
0x40
:
max_segs
=
16
;
break
;
case
0x50
:
max_segs
=
32
;
break
;
case
0x60
:
max_segs
=
64
;
break
;
case
0x70
:
max_segs
=
65
;
break
;
default
:
break
;
}
return
max_segs
;
}
/**
* Decode the given octed into a maximum APDU value.
*
* @param octet From clause 20.1.2.4 max-segments-accepted
* and clause 20.1.2.5 max-APDU-length-accepted
*
* @return Returns the maximum APDU value.
*/
int
decode_max_apdu
(
uint8_t
octet
)
{
int
max_apdu
=
0
;
switch
(
octet
&
0x0F
) {
case
0
:
max_apdu
=
50
;
break
;
case
1
:
max_apdu
=
128
;
break
;
case
2
:
max_apdu
=
206
;
break
;
case
3
:
max_apdu
=
480
;
break
;
case
4
:
max_apdu
=
1024
;
break
;
case
5
:
max_apdu
=
1476
;
break
;
default
:
break
;
}
return
max_apdu
;
}
/**
* Encode a BACnet tag and returns the number of bytes consumed.
* (From clause 20.2.1 General Rules for Encoding BACnet Tags)
*
* @param apdu Pointer to the encode buffer, or NULL for length
* @param tag_number Number of the tag to encode,
* see BACNET_APPLICATION_TAG_X macros.
* @param context_specific Indicates to encode in the given context.
* @param len_value_type Indicates the length of the tag's content.
*
* @return Returns the number of apdu bytes consumed.
*/
int
encode_tag
(
uint8_t
*
apdu
,
uint8_t
tag_number
,
bool
context_specific
,
uint32_t
len_value_type
)
{
int
len
=
1
;
/* return value */
uint8_t
*
apdu_offset
=
NULL
;
if
(
apdu
) {
apdu
[
0
]
=
0
;
}
if
(
context_specific
) {
if
(
apdu
) {
apdu
[
0
]
=
BIT
(
3
);
}
}
/* additional tag byte after this byte */
/* for extended tag byte */
if
(
tag_number
<=
14
) {
if
(
apdu
) {
apdu
[
0
] |= (
tag_number
<<
4
);
}
}
else
{
if
(
apdu
) {
apdu
[
0
] |=
0xF0
;
apdu
[
1
]
=
tag_number
;
}
len
++
;
}
/* NOTE: additional len byte(s) after extended tag byte */
/* if larger than 4 */
if
(
len_value_type
<=
4
) {
if
(
apdu
) {
apdu
[
0
] |=
len_value_type
;
}
}
else
{
if
(
apdu
) {
apdu
[
0
] |=
5
;
}
if
(
len_value_type
<=
253
) {
if
(
apdu
) {
apdu
[
len
]
=
(
uint8_t
)
len_value_type
;
}
len
++
;
}
else
if
(
len_value_type
<=
65535
) {
if
(
apdu
) {
apdu
[
len
]
=
254
;
}
len
++
;
if
(
apdu
) {
apdu_offset
=
&
apdu
[
len
];
}
len
+=
encode_unsigned16
(
apdu_offset
, (
uint16_t
)
len_value_type
);
}
else
{
if
(
apdu
) {
apdu
[
len
]
=
255
;
}
len
++
;
if
(
apdu
) {
apdu_offset
=
&
apdu
[
len
];
}
len
+=
encode_unsigned32
(
apdu_offset
,
len_value_type
);
}
}
return
len
;
}
/**
* @brief Encode a BACnet opening tag and returns the number
* of bytes consumed. From clause 20.2.1.3.2 Constructed Data.
*
* An "opening" tag whose Tag Number field shall contain the value
* of the tag number, whose Class field shall indicate
* "context specific," and whose length/value/type field shall
* have the value B'110';
*
* @param apdu Pointer to the encode buffer, or NULL for length
* @param tag_number Number of the tag to encode,
* see BACNET_APPLICATION_TAG_X macros.
*
* @return Returns the number of apdu bytes consumed.
*/
int
encode_opening_tag
(
uint8_t
*
apdu
,
uint8_t
tag_number
)
{
int
len
=
1
;
if
(
apdu
) {
/* set class field to context specific */
apdu
[
0
]
=
BIT
(
3
);
}
/* additional tag byte after this byte for extended tag byte */
if
(
tag_number
<=
14
) {
if
(
apdu
) {
apdu
[
0
] |= (
tag_number
<<
4
);
}
}
else
{
if
(
apdu
) {
apdu
[
0
] |=
0xF0
;
apdu
[
1
]
=
tag_number
;
}
len
++
;
}
if
(
apdu
) {
/* set type field to opening tag */
apdu
[
0
] |=
6
;
}
return
len
;
}
/**
* Encode a BACnet closing tag and returns the number
* of bytes consumed. From clause 20.2.1.3.2 Constructed Data:
*
* A "closing" tag, whose Class and Tag Number fields shall
* contain the same values as the "opening" tag and whose
* length/value/type field shall have the value B'111'.
*
* @param apdu Pointer to the encode buffer, or NULL for length
* @param tag_number Number of the tag to encode,
* see BACNET_APPLICATION_TAG_X macros.
*
* @return Returns the number of apdu bytes consumed.
*/
int
encode_closing_tag
(
uint8_t
*
apdu
,
uint8_t
tag_number
)
{
int
len
=
1
;
/* set class field to context specific */
if
(
apdu
) {
apdu
[
0
]
=
BIT
(
3
);
}
/* additional tag byte after this byte for extended tag byte */
if
(
tag_number
<=
14
) {
if
(
apdu
) {
apdu
[
0
] |= (
tag_number
<<
4
);
}
}
else
{
if
(
apdu
) {
apdu
[
0
] |=
0xF0
;
apdu
[
1
]
=
tag_number
;
}
len
++
;
}
if
(
apdu
) {
/* set type field to closing tag */
apdu
[
0
] |=
7
;
}
return
len
;
}
#if
defined(
BACNET_STACK_DEPRECATED_DISABLE
)
/**
* Decode a BACnet tag and returns the number of bytes consumed.
*
* @param apdu Pointer to the encode buffer
* @param tag_number Place holder for number of the tag decoded
* see BACNET_APPLICATION_TAG_X macros.
*
* @return Returns the number of apdu bytes consumed.
* @deprecated Use bacnet_tag_number_decode() instead
*/
int
decode_tag_number
(
const
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
;
}
#endif
/**
* @brief Decode the BACnet Tag Number
* as defined in clause 20.2.1.2 Tag Number
*
* Bit Number:
* 7 6 5 4 3 2 1 0
* |-----|-----|-----|-----|-----|-----|-----|-----|
* | Tag Number |Class|Length/Value/Type|
* |-----|-----|-----|-----|-----|-----|-----|-----|
*
* Tag numbers ranging from zero to 14 (inclusive) shall be encoded
* in the Tag Number field of the initial octet as a four bit
* binary integer with bit 7 the most significant bit.
*
* Tag numbers ranging from 15 to 254 (inclusive) shall be encoded by
* setting the Tag Number field of the initial octet to B'1111'
* and following the initial tag octet by an octet containing the
* tag number represented as an eight-bit binary integer with bit 7 the
* most significant bit.
*
* The encoding does not allow, nor does BACnet require, tag numbers
* larger than 254. The value B'11111111' of the subsequent
* octet is reserved by ASHRAE.
*
* @param apdu - buffer to hold the bytes
* @param apdu_size - number of bytes in the buffer to decode
* @param tag_number - BACnet tag number
*
* @return number of bytes decoded, or zero if errors occur
*/
int
bacnet_tag_number_decode
(
const
uint8_t
*
apdu
,
uint32_t
apdu_size
,
uint8_t
*
tag_number
)
{
int
len
=
0
;
/* return value */
if
(
apdu_size
>=
1
) {
if
(
IS_EXTENDED_TAG_NUMBER
(
apdu
[
0
])) {
if
(
apdu_size
>=
2
) {
/* extended tag */
if
(
tag_number
) {
*
tag_number
=
apdu
[
1
];
}
len
=
2
;
}
else
{
/* malfomed */
len
=
0
;
}
}
else
{
if
(
tag_number
) {
*
tag_number
=
(
uint8_t
)(
apdu
[
0
] >>
4
);
}
len
=
1
;
}
}
return
len
;
}
/**
* @brief Encode a BACnet BACnet Tag Number and Value
* as defined in clause 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the data to be encoded, or NULL for length
* @param apdu_size - number of bytes in the buffer
* @param tag - tag value to encode
*
* @return returns the number of apdu bytes consumed,
* or 0 if apdu_size is too small to fit the data
*/
int
bacnet_tag_encode
(
uint8_t
*
apdu
,
uint32_t
apdu_size
,
const
BACNET_TAG
*
tag
)
{
int
apdu_len
=
0
;
/* total length of the apdu, return value */
if
(!
tag
) {
return
0
;
}
if
(
tag
->
application
) {
apdu_len
=
encode_tag
(
NULL
,
tag
->
number
, false,
tag
->
len_value_type
);
}
else
if
(
tag
->
context
) {
apdu_len
=
encode_tag
(
NULL
,
tag
->
number
, true,
tag
->
len_value_type
);
}
else
if
(
tag
->
opening
) {
apdu_len
=
encode_opening_tag
(
NULL
,
tag
->
number
);
}
else
if
(
tag
->
closing
) {
apdu_len
=
encode_closing_tag
(
NULL
,
tag
->
number
);
}
if
(
apdu_len
>
apdu_size
) {
apdu_len
=
0
;
}
else
{
if
(
tag
->
application
) {
apdu_len
=
encode_tag
(
apdu
,
tag
->
number
, false,
tag
->
len_value_type
);
}
else
if
(
tag
->
context
) {
apdu_len
=
encode_tag
(
apdu
,
tag
->
number
, true,
tag
->
len_value_type
);
}
else
if
(
tag
->
opening
) {
apdu_len
=
encode_opening_tag
(
apdu
,
tag
->
number
);
}
else
if
(
tag
->
closing
) {
apdu_len
=
encode_closing_tag
(
apdu
,
tag
->
number
);
}
}
return
apdu_len
;
}
/**
* @brief Decode the BACnet Tag Number and Value
* as defined in clause 20.2.1 General Rules For Encoding BACnet Tags
*
* @param apdu - buffer of data to be decoded
* @param apdu_size - number of bytes in the buffer
* @param tag - decoded tag data, if decoded
*
* @return the number of apdu bytes consumed, or zero if malformed
*/
int
bacnet_tag_decode
(
const
uint8_t
*
apdu
,
uint32_t
apdu_size
,
BACNET_TAG
*
tag
)
{
int
len
=
0
;
uint8_t
tag_number
=
0
;
bool
application_tag
=
false;
bool
context_tag
=
false;
bool
opening_tag
=
false;
bool
closing_tag
=
false;
uint32_t
len_value_type
=
0
;
if
(
apdu
&&
(
apdu_size
>
0
)) {
len
=
bacnet_tag_number_decode
(
&
apdu
[
0
],
apdu_size
,
&
tag_number
);
}
if
(
len
>
0
) {
if
(
IS_EXTENDED_VALUE
(
apdu
[
0
])) {
if
(
apdu_size
>
len
) {
apdu_size
-=
len
;
if
((
apdu
[
len
]
==
255
)
&&
(
apdu_size
>=
5
)) {
/* tagged as uint32_t */
uint32_t
value32
;
len
++
;
len
+=
decode_unsigned32
(
&
apdu
[
len
],
&
value32
);
len_value_type
=
value32
;
}
else
if
((
apdu
[
len
]
==
254
)
&&
(
apdu_size
>=
3
)) {
/* tagged as uint16_t */
uint16_t
value16
;
len
++
;
len
+=
decode_unsigned16
(
&
apdu
[
len
],
&
value16
);
len_value_type
=
value16
;
}
else
if
((
apdu
[
len
]
<
254
)
&&
(
apdu_size
>=
1
)) {
/* no tag - must be uint8_t */
len_value_type
=
apdu
[
len
];
len
++
;
}
else
{
/* packet is malformed */
len
=
0
;
}
}
else
{
/* packet is malformed */
len
=
0
;
}
}
else
if
(
IS_OPENING_TAG
(
apdu
[
0
])) {
/* reserved value */
}
else
if
(
IS_CLOSING_TAG
(
apdu
[
0
])) {
/* reserved value */
}
else
{
/* small value */
len_value_type
=
apdu
[
0
]
&
0x07
;
}
if
(
IS_CONTEXT_SPECIFIC
(
apdu
[
0
])) {
if
(
IS_OPENING_TAG
(
apdu
[
0
])) {
opening_tag
=
true;
}
else
if
(
IS_CLOSING_TAG
(
apdu
[
0
])) {
closing_tag
=
true;
}
else
{
context_tag
=
true;
}
}
else
{
application_tag
=
true;
}
if
((
len
>
0
)
&&
tag
) {
tag
->
number
=
tag_number
;
tag
->
application
=
application_tag
;
tag
->
context
=
context_tag
;
tag
->
opening
=
opening_tag
;
tag
->
closing
=
closing_tag
;
tag
->
len_value_type
=
len_value_type
;
}
}
return
len
;
}
#if
defined(
BACNET_STACK_DEPRECATED_DISABLE
)
/**
* @brief Returns if at the given pointer a
* opening tag has been found.
* @param apdu Pointer to the tag number.
* @return true/false
* @deprecated Use bacnet_is_opening_tag() instead
*/
bool
decode_is_opening_tag
(
const
uint8_t
*
apdu
)
{
return
(
bool
)((
apdu
[
0
]
&
0x07
)
==
6
);
}
#endif
/**
* @brief Returns true if an opening tag has been found.
*
* @param apdu Pointer to the tag number.
* @param apdu_size Number of bytes available to decode
*
* @return true if an opening tag has been found.
*/
bool
bacnet_is_opening_tag
(
const
uint8_t
*
apdu
,
uint32_t
apdu_size
)
{
bool
tag
=
false;
if
(
apdu_size
>
0
) {
if
(
IS_CONTEXT_SPECIFIC
(
apdu
[
0
])
&&
(
IS_OPENING_TAG
(
apdu
[
0
]))) {
tag
=
true;
}
}
return
tag
;
}
#if
defined(
BACNET_STACK_DEPRECATED_DISABLE
)
/**
* @brief Returns if at the given pointer a
* closing tag has been found.
* @param apdu Pointer to the tag number.
* @return true/false
* @deprecated Use bacnet_is_closing_tag() instead
*/
bool
decode_is_closing_tag
(
const
uint8_t
*
apdu
)
{
return
(
bool
)((
apdu
[
0
]
&
0x07
)
==
7
);
}
#endif
/**
* @brief Returns true if a closing tag has been found.
*
* @param apdu Pointer to the tag number.
* @param apdu_size Number of bytes available to decode
*
* @return true if a closing tag has been found.
*/
bool
bacnet_is_closing_tag
(
const
uint8_t
*
apdu
,
uint32_t
apdu_size
)
{
bool
tag
=
false;
if
(
apdu_size
>
0
) {
if
(
IS_CONTEXT_SPECIFIC
(
apdu
[
0
])
&&
(
IS_CLOSING_TAG
(
apdu
[
0
]))) {
tag
=
true;
}
}
return
tag
;
}
/**
* @brief Returns true if a context specific tag has been found.
*
* @param apdu Pointer to the tag number.
* @param apdu_size Number of bytes available to decode
*
* @return true if a context specific tag has been found.
*/
bool
bacnet_is_context_specific
(
const
uint8_t
*
apdu
,
uint32_t
apdu_size
)
{
bool
tag
=
false;
if
(
apdu_size
>
0
) {
if
(
IS_CONTEXT_SPECIFIC
(
apdu
[
0
])) {
tag
=
true;
}
}
return
tag
;
}
#if
defined(
BACNET_STACK_DEPRECATED_DISABLE
)
/**
* @brief Decodes the tag number and the value,
* that the APDU pointer is addressing.
* (From clause 20.2.1.3.2 Constructed Data)
*
* @param apdu Pointer to the message buffer.
* @param tag_number Pointer to a variable
* taking the tag number.
* @param value Pointer to a variable
* taking the value.
*
* @return number of bytes decoded, or zero if errors occur
* @deprecated Use bacnet_tag_decode() instead
*/
int
decode_tag_number_and_value
(
const
uint8_t
*
apdu
,
uint8_t
*
tag_number
,
uint32_t
*
value
)
{
int
len
=
1
;
uint16_t
value16
;
uint32_t
value32
;
len
=
decode_tag_number
(
&
apdu
[
0
],
tag_number
);
if
(
IS_EXTENDED_VALUE
(
apdu
[
0
])) {
/* tagged as uint32_t */
if
(
apdu
[
len
]
==
255
) {
len
++
;
value32
=
0
;
len
+=
decode_unsigned32
(
&
apdu
[
len
],
&
value32
);
if
(
value
) {
*
value
=
value32
;
}
}
/* tagged as uint16_t */
else
if
(
apdu
[
len
]
==
254
) {
len
++
;
value16
=
0
;
len
+=
decode_unsigned16
(
&
apdu
[
len
],
&
value16
);
if
(
value
) {
*
value
=
value16
;
}
}
/* no tag - must be uint8_t */
else
{
if
(
value
) {
*
value
=
apdu
[
len
];
}
len
++
;
}
}
else
if
(
IS_OPENING_TAG
(
apdu
[
0
])
&&
value
) {
/* opening tag */
*
value
=
0
;
}
else
if
(
IS_CLOSING_TAG
(
apdu
[
0
])
&&
value
) {
/* closing tag */
*
value
=
0
;
}
else
if
(
value
) {
/* small value */
*
value
=
apdu
[
0
]
&
0x07
;
}
return
len
;
}
#endif
#if
defined(
BACNET_STACK_DEPRECATED_DISABLE
)
/**
* @brief Decode the BACnet Tag Number and Value
* as defined in clause 20.2.1.3.2 Constructed Data
*
* @param apdu - buffer of data to be decoded
* @param apdu_size - number of bytes in the buffer
* @param tag_number - decoded tag number, if decoded
* @param value - decoded value, if decoded
*
* @return the number of apdu bytes consumed, or zero if errors occur
* @deprecated use bacnet_tag_decode() instead
*/
int
bacnet_tag_number_and_value_decode
(
const
uint8_t
*
apdu
,
uint32_t
apdu_size
,
uint8_t
*
tag_number
,
uint32_t
*
value
)
{
int
len
=
0
;
BACNET_TAG
tag
=
{
0
};
len
=
bacnet_tag_decode
(
apdu
,
apdu_size
,
&
tag
);
if
(
len
>
0
) {
if
(
value
) {
*
value
=
tag
.
len_value_type
;
}
if
(
value
) {
*
tag_number
=
tag
.
number
;
}
}
return
len
;
}
#endif
/**
* @brief Determine the data length from the application tag number
* @param tag_number application tag number to be evaluated.
* @param len_value_type Length of the data in bytes.
* @return datalength for the given tag, or INT_MAX if out of range.
*/
int
bacnet_application_data_length
(
uint8_t
tag_number
,
uint32_t
len_value_type
)
{
int
len
=
0
;
switch
(
tag_number
) {
case
BACNET_APPLICATION_TAG_NULL
:
break
;
case
BACNET_APPLICATION_TAG_BOOLEAN
:
break
;
case
BACNET_APPLICATION_TAG_UNSIGNED_INT
:
case
BACNET_APPLICATION_TAG_SIGNED_INT
:
case
BACNET_APPLICATION_TAG_REAL
:
case
BACNET_APPLICATION_TAG_DOUBLE
:
case
BACNET_APPLICATION_TAG_OCTET_STRING
:
case
BACNET_APPLICATION_TAG_CHARACTER_STRING
:
case
BACNET_APPLICATION_TAG_BIT_STRING
:
case
BACNET_APPLICATION_TAG_ENUMERATED
:
case
BACNET_APPLICATION_TAG_DATE
:
case
BACNET_APPLICATION_TAG_TIME
:
case
BACNET_APPLICATION_TAG_OBJECT_ID
:
len
=
INT_MAX
;
if
(
len_value_type
<
INT_MAX
) {
len
=
(
int
)
len_value_type
;
}
break
;
default
:
break
;
}
return
len
;
}
/**
* @brief Returns the length of data between an opening tag and a closing tag.
* @note Expects that the first octet contain the opening tag.
* @param apdu Pointer to the APDU buffer
* @param apdu_size Bytes valid in the buffer
* @param property ID of the property to get the length for.
* @return length of data between an opening tag and a closing tag 0..N,
* or BACNET_STATUS_ERROR.
*/
int
bacnet_enclosed_data_length
(
const
uint8_t
*
apdu
,
size_t
apdu_size
)
{
int
len
=
0
;
int
total_len
=
0
;
int
apdu_len
=
0
;
BACNET_TAG
tag
=
{
0
};
uint8_t
opening_tag_number
=
0
;
size_t
opening_tag_number_counter
=
0
;
bool
total_len_enable
=
false;
if
(!
apdu
) {
return
BACNET_STATUS_ERROR
;
}
if
(
apdu_size
<=
apdu_len
) {
/* error: exceeding our buffer limit */
return
BACNET_STATUS_ERROR
;
}
if
(!
bacnet_is_opening_tag
(
apdu
,
apdu_size
)) {
/* error: opening tag is missing */
return
BACNET_STATUS_ERROR
;
}
do
{
len
=
bacnet_tag_decode
(
apdu
,
apdu_size
-
apdu_len
,
&
tag
);
if
(
len
==
0
) {
return
BACNET_STATUS_ERROR
;
}
if
(
tag
.
opening
) {
if
(
opening_tag_number_counter
==
0
) {
opening_tag_number
=
tag
.
number
;
opening_tag_number_counter
=
1
;
total_len_enable
=
false;
}
else
if
(
tag
.
number
==
opening_tag_number
) {
total_len_enable
=
true;
opening_tag_number_counter
++
;
}
else
{
total_len_enable
=
true;
}
}
else
if
(
tag
.
closing
) {
if
(
tag
.
number
==
opening_tag_number
) {
if
(
opening_tag_number_counter
>
0
) {
opening_tag_number_counter
--
;
}
}
total_len_enable
=
true;
}
else
if
(
tag
.
context
) {
/* note: bound the SUM, not only the addend: len already holds
the size of this tag's header */
if
(
tag
.
len_value_type
>
(
uint32_t
)(
INT_MAX
-
len
)) {
/* error: length is out of range */
return
BACNET_STATUS_ERROR
;
}
len
+=
tag
.
len_value_type
;
total_len_enable
=
true;
}
else
{
if
(
tag
.
len_value_type
>
(
uint32_t
)(
INT_MAX
-
len
)) {
/* error: length is out of range */
return
BACNET_STATUS_ERROR
;
}
/* application tagged data */
len
+=
bacnet_application_data_length
(
tag
.
number
,
tag
.
len_value_type
);
total_len_enable
=
true;
}
if
(
opening_tag_number_counter
>
0
) {
if
(
len
>
0
) {
if
(
total_len_enable
) {
if
(
len
>
(
INT_MAX
-
total_len
)) {
/* error: length is out of range */
return
BACNET_STATUS_ERROR
;
}
total_len
+=
len
;
}
}
else
{
/* error: len is not incrementing */
return
BACNET_STATUS_ERROR
;
}
if
(
len
>
(
INT_MAX
-
apdu_len
)) {
/* error: length is out of range */
return
BACNET_STATUS_ERROR
;
}
apdu_len
+=
len
;
if
(
apdu_size
<=
apdu_len
) {
/* error: exceeding our buffer limit */
return
BACNET_STATUS_ERROR
;
}
apdu
+=
len
;
}
}
while
(
opening_tag_number_counter
>
0
);
return
total_len
;
}
#if
defined(
BACNET_STACK_DEPRECATED_DISABLE
)
/**
* @brief Returns true if the tag is context specific
* and matches, as defined in clause 20.2.1.3.2 Constructed
* Data.
*
* @param apdu Pointer to the tag begin.
* @param tag_number Tag number, that has been decoded before.
*
* @return true on a match, false otherwise.
* @deprecated Use bacnet_is_context_tag_number() instead
*/
bool
decode_is_context_tag
(
const
uint8_t
*
apdu
,
uint8_t
tag_number
)
{
uint8_t
my_tag_number
=
0
;
decode_tag_number
(
apdu
,
&
my_tag_number
);
return
(
bool
)(
IS_CONTEXT_SPECIFIC
(
*
apdu
)
&&
(
my_tag_number
==
tag_number
));
}
#endif
#if
defined(
BACNET_STACK_DEPRECATED_DISABLE
)
/**
* @brief Returns true if the tag is context specific
* and matches, as defined in clause 20.2.1.3.2 Constructed
* Data. This function returns the tag length as well.
*
* @param apdu Pointer to the tag begin.
* @param tag_number Tag number, that has been decoded before.
* @param tag_length Pointer to a variable, taking the
* length of the tag in bytes.
*
* @return true on a match, false otherwise.
* @deprecated Use bacnet_is_context_tag_number() instead
*/
bool
decode_is_context_tag_with_length
(
const
uint8_t
*
apdu
,
uint8_t
tag_number
,
int
*
tag_length
)
{
uint8_t
my_tag_number
=
0
;
*
tag_length
=
decode_tag_number
(
apdu
,
&
my_tag_number
);
return
(
bool
)(
IS_CONTEXT_SPECIFIC
(
*
apdu
)
&&
(
my_tag_number
==
tag_number
));
}
#endif
/**
* @brief Returns true if the tag is context specific
* and matches, as defined in clause 20.2.1.3.2 Constructed
* Data. This function returns the tag length as well.
*
* @param apdu Pointer to the tag begin.
* @param apdu_size - number of bytes in the buffer
* @param tag_number Tag number, that has been decoded before.
* @param tag_length Pointer to a variable, or NULL.
* Returns the length of the tag in bytes if not NULL.
* @param len_value_type Pointer to a variable, or NULL.
* Returns the len_value_type of the tag in bytes if not NULL.
*
* @return true on a match, false otherwise.
*/
bool
bacnet_is_context_tag_number
(
const
uint8_t
*
apdu
,
uint32_t
apdu_size
,
uint8_t
tag_number
,
int
*
tag_length
,
uint32_t
*
len_value_type
)
{
bool
match
=
false;
int
len
;
BACNET_TAG
tag
=
{
0
};
len
=
bacnet_tag_decode
(
apdu
,
apdu_size
,
&
tag
);
if
(
len
>
0
) {
if
(
tag
.
context
&&
(
tag
.
number
==
tag_number
)) {
if
(
tag_length
) {
*
tag_length
=
len
;
}
if
(
len_value_type
) {
*
len_value_type
=
tag
.
len_value_type
;
}
match
=
true;
}
}
return
match
;
}
View remainder of file in raw view
Back
|
FazBrowse Home
|
New Git URL