1use bacnet_types::constructed::BACnetAddress;
12use bacnet_types::enums::{NetworkPriority, RejectMessageReason};
13use bacnet_types::error::Error;
14use bacnet_types::MacAddr;
15use bytes::{BufMut, Bytes, BytesMut};
16
17mod decode_error;
18pub use decode_error::{NpduAddressField, NpduDecodeError};
19
20pub const BACNET_PROTOCOL_VERSION: u8 = 1;
22
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
31pub struct NpduAddress {
32 pub network: u16,
34 pub mac_address: MacAddr,
36}
37
38impl NpduAddress {
39 pub const MAX_MAC_LEN: usize = BACnetAddress::MAX_MAC_LEN;
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct Npdu {
58 pub is_network_message: bool,
60 pub expecting_reply: bool,
62 pub priority: NetworkPriority,
64 pub destination: Option<NpduAddress>,
66 pub source: Option<NpduAddress>,
68 pub hop_count: u8,
70 pub message_type: Option<u8>,
72 pub vendor_id: Option<u16>,
74 pub payload: Bytes,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83pub struct RejectMessageToNetwork {
84 pub reason: RejectMessageReason,
86 pub dnet: u16,
88}
89
90impl Default for Npdu {
91 fn default() -> Self {
92 Self {
93 is_network_message: false,
94 expecting_reply: false,
95 priority: NetworkPriority::NORMAL,
96 destination: None,
97 source: None,
98 hop_count: 255,
99 message_type: None,
100 vendor_id: None,
101 payload: Bytes::new(),
102 }
103 }
104}
105
106pub fn encode_npdu(buf: &mut BytesMut, npdu: &Npdu) -> Result<(), Error> {
112 buf.put_u8(BACNET_PROTOCOL_VERSION);
113
114 let mut control: u8 = npdu.priority.to_raw() & 0x03;
115 if npdu.is_network_message {
116 control |= 0x80;
117 }
118 if npdu.destination.is_some() {
119 control |= 0x20;
120 }
121 if npdu.source.is_some() {
122 control |= 0x08;
123 }
124 if npdu.expecting_reply {
125 control |= 0x04;
126 }
127 buf.put_u8(control);
128
129 if let Some(dest) = &npdu.destination {
130 if dest.network == 0 {
131 return Err(Error::Encoding("NPDU DNET must not be 0".into()));
132 }
133 buf.put_u16(dest.network);
134 check_encoded_len(NpduAddressField::Destination, &dest.mac_address)?;
135 buf.put_u8(dest.mac_address.len() as u8);
136 buf.put_slice(&dest.mac_address);
137 }
138
139 if let Some(src) = &npdu.source {
140 if src.network == 0 || src.network == 0xFFFF {
141 return Err(Error::Encoding(format!(
142 "NPDU SNET must be 1..65534, got {}",
143 src.network
144 )));
145 }
146 if src.mac_address.is_empty() {
147 return Err(Error::Encoding("NPDU SLEN must not be 0".into()));
148 }
149 buf.put_u16(src.network);
150 check_encoded_len(NpduAddressField::Source, &src.mac_address)?;
151 buf.put_u8(src.mac_address.len() as u8);
152 buf.put_slice(&src.mac_address);
153 }
154
155 if npdu.destination.is_some() {
156 buf.put_u8(npdu.hop_count);
157 }
158
159 if npdu.is_network_message {
160 if let Some(msg_type) = npdu.message_type {
161 buf.put_u8(msg_type);
162 if msg_type >= 0x80 {
163 buf.put_u16(npdu.vendor_id.unwrap_or(0));
164 }
165 }
166 }
167
168 buf.put_slice(&npdu.payload);
169
170 Ok(())
171}
172
173fn check_encoded_len(field: NpduAddressField, mac: &[u8]) -> Result<(), Error> {
175 if mac.len() > NpduAddress::MAX_MAC_LEN {
176 return Err(Error::Encoding(format!(
177 "NPDU {field} address of {} octets exceeds the {}-octet limit",
178 mac.len(),
179 NpduAddress::MAX_MAC_LEN
180 )));
181 }
182 Ok(())
183}
184
185pub fn decode_npdu(data: Bytes) -> Result<Npdu, NpduDecodeError> {
201 if data.len() < 2 {
202 return Err(Error::buffer_too_short(2, data.len()).into());
203 }
204
205 let version = data[0];
206 if version != BACNET_PROTOCOL_VERSION {
207 return Err(
208 Error::decoding(0, format!("unsupported BACnet protocol version: {version}")).into(),
209 );
210 }
211
212 let control = data[1];
213 let is_network_message = control & 0x80 != 0;
214 let has_destination = control & 0x20 != 0;
215 let has_source = control & 0x08 != 0;
216 let expecting_reply = control & 0x04 != 0;
217 let priority = NetworkPriority::from_raw(control & 0x03);
218
219 #[cfg(feature = "std")]
221 if control & 0x50 != 0 {
222 tracing::warn!(
223 control_byte = control,
224 "NPDU control byte has reserved bits set (bits 4 or 6)"
225 );
226 }
227
228 let mut offset = 2;
229 let mut destination = None;
230 let mut source = None;
231 let mut hop_count: u8 = 255;
232
233 if has_destination {
234 if offset + 3 > data.len() {
235 return Err(Error::decoding(offset, "NPDU too short for destination fields").into());
236 }
237 let dnet = u16::from_be_bytes([data[offset], data[offset + 1]]);
238 if dnet == 0 {
239 return Err(Error::decoding(offset, "NPDU destination network 0 is invalid").into());
240 }
241 offset += 2;
242 let dlen = data[offset];
243 offset += 1;
244 let dadr = match decode_address(&data, offset, NpduAddressField::Destination, dlen, dnet) {
245 Ok(dadr) => dadr,
246 Err(mut refused) => {
247 if let NpduDecodeError::AddressTooLong { source, .. } = &mut refused {
248 *source = has_source
249 .then(|| source_behind(&data, offset + usize::from(dlen)))
250 .flatten();
251 }
252 return Err(refused);
253 }
254 };
255 offset += dadr.len();
256
257 destination = Some(NpduAddress {
258 network: dnet,
259 mac_address: dadr,
260 });
261 }
262
263 if has_source {
264 if offset + 3 > data.len() {
265 return Err(Error::decoding(offset, "NPDU too short for source fields").into());
266 }
267 let snet = u16::from_be_bytes([data[offset], data[offset + 1]]);
268 if snet == 0 {
269 return Err(Error::decoding(offset, "NPDU source network 0 is invalid").into());
270 }
271 if snet == 0xFFFF {
272 return Err(Error::decoding(offset, "NPDU source network 0xFFFF is invalid").into());
273 }
274 offset += 2;
275 let slen = data[offset];
276 offset += 1;
277
278 if slen == 0 {
279 return Err(Error::decoding(offset - 1, "NPDU source SLEN=0 is invalid").into());
280 }
281 let dnet = destination.as_ref().map(|d| d.network);
282 let sadr = decode_address(&data, offset, NpduAddressField::Source, slen, dnet)?;
283 offset += sadr.len();
284
285 source = Some(NpduAddress {
286 network: snet,
287 mac_address: sadr,
288 });
289 }
290
291 if has_destination {
292 if offset >= data.len() {
293 return Err(Error::decoding(offset, "NPDU too short for hop count").into());
294 }
295 hop_count = data[offset];
296 offset += 1;
297 }
298
299 let mut message_type = None;
300 let mut vendor_id = None;
301
302 if is_network_message {
303 if offset >= data.len() {
304 return Err(Error::decoding(offset, "NPDU too short for network message type").into());
305 }
306 let msg_type = data[offset];
307 offset += 1;
308 message_type = Some(msg_type);
309
310 if msg_type >= 0x80 {
311 if offset + 2 > data.len() {
312 return Err(
313 Error::decoding(offset, "NPDU too short for proprietary vendor ID").into(),
314 );
315 }
316 vendor_id = Some(u16::from_be_bytes([data[offset], data[offset + 1]]));
317 offset += 2;
318 }
319 }
320
321 let payload = data.slice(offset..);
322
323 Ok(Npdu {
324 is_network_message,
325 expecting_reply,
326 priority,
327 destination,
328 source,
329 hop_count,
330 message_type,
331 vendor_id,
332 payload,
333 })
334}
335
336fn decode_address(
340 data: &[u8],
341 offset: usize,
342 field: NpduAddressField,
343 length: u8,
344 dnet: impl Into<Option<u16>>,
345) -> Result<MacAddr, NpduDecodeError> {
346 if usize::from(length) > NpduAddress::MAX_MAC_LEN {
347 return Err(NpduDecodeError::AddressTooLong {
348 field,
349 length,
350 dnet: dnet.into(),
351 source: None,
352 });
353 }
354 let end = offset + usize::from(length);
355 if end > data.len() {
356 return Err(Error::decoding(
357 offset,
358 format!(
359 "NPDU {field} address truncated: {}={length}",
360 field.length_octet()
361 ),
362 )
363 .into());
364 }
365 Ok(MacAddr::from_slice(&data[offset..end]))
366}
367
368fn source_behind(data: &[u8], offset: usize) -> Option<NpduAddress> {
375 let header = data.get(offset..offset + 3)?;
376 let network = u16::from_be_bytes([header[0], header[1]]);
377 let length = usize::from(header[2]);
378 if network == 0 || network == 0xFFFF || length == 0 || length > NpduAddress::MAX_MAC_LEN {
379 return None;
380 }
381 let sadr = data.get(offset + 3..offset + 3 + length)?;
382 Some(NpduAddress {
383 network,
384 mac_address: MacAddr::from_slice(sadr),
385 })
386}
387
388pub fn decode_reject_message_to_network(payload: &[u8]) -> Result<RejectMessageToNetwork, Error> {
394 if payload.len() != 3 {
395 return Err(Error::decoding(
396 0,
397 format!(
398 "Reject-Message-To-Network payload must be exactly 3 octets, got {}",
399 payload.len()
400 ),
401 ));
402 }
403 Ok(RejectMessageToNetwork {
404 reason: RejectMessageReason::from_raw(payload[0]),
405 dnet: u16::from_be_bytes([payload[1], payload[2]]),
406 })
407}
408
409#[cfg(test)]
414mod address_bound_tests;
415
416#[cfg(test)]
417mod tests {
418 use super::*;
419
420 fn encode_to_vec(npdu: &Npdu) -> Vec<u8> {
421 let mut buf = BytesMut::with_capacity(64);
422 encode_npdu(&mut buf, npdu).unwrap();
423 buf.to_vec()
424 }
425
426 #[test]
427 fn minimal_local_apdu() {
428 let npdu = Npdu {
430 payload: Bytes::from_static(&[0x10, 0x08]), ..Default::default()
432 };
433 let encoded = encode_to_vec(&npdu);
434 assert_eq!(encoded, vec![0x01, 0x00, 0x10, 0x08]);
436
437 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
438 assert_eq!(decoded, npdu);
439 }
440
441 #[test]
442 fn expecting_reply_flag() {
443 let npdu = Npdu {
444 expecting_reply: true,
445 payload: Bytes::from_static(&[0xAA]),
446 ..Default::default()
447 };
448 let encoded = encode_to_vec(&npdu);
449 assert_eq!(encoded[1], 0x04); let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
451 assert!(decoded.expecting_reply);
452 }
453
454 #[test]
455 fn priority_encoding() {
456 for (prio, expected_bits) in [
457 (NetworkPriority::NORMAL, 0x00),
458 (NetworkPriority::URGENT, 0x01),
459 (NetworkPriority::CRITICAL_EQUIPMENT, 0x02),
460 (NetworkPriority::LIFE_SAFETY, 0x03),
461 ] {
462 let npdu = Npdu {
463 priority: prio,
464 payload: Bytes::new(),
465 ..Default::default()
466 };
467 let encoded = encode_to_vec(&npdu);
468 assert_eq!(encoded[1] & 0x03, expected_bits);
469 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
470 assert_eq!(decoded.priority, prio);
471 }
472 }
473
474 #[test]
475 fn destination_only_round_trip() {
476 let npdu = Npdu {
477 destination: Some(NpduAddress {
478 network: 1000,
479 mac_address: MacAddr::from_slice(&[0x0A, 0x00, 0x01, 0x01, 0xBA, 0xC0]),
480 }),
481 hop_count: 254,
482 payload: Bytes::from_static(&[0x10, 0x08]),
483 ..Default::default()
484 };
485 let encoded = encode_to_vec(&npdu);
486 assert_eq!(encoded[1] & 0x20, 0x20);
488 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
489 assert_eq!(decoded, npdu);
490 }
491
492 #[test]
493 fn destination_broadcast() {
494 let npdu = Npdu {
496 destination: Some(NpduAddress {
497 network: 0xFFFF,
498 mac_address: MacAddr::new(),
499 }),
500 hop_count: 255,
501 payload: Bytes::from_static(&[0x10, 0x08]),
502 ..Default::default()
503 };
504 let encoded = encode_to_vec(&npdu);
505 assert_eq!(encoded.len(), 8);
507 assert_eq!(&encoded[2..4], &[0xFF, 0xFF]);
509 assert_eq!(encoded[4], 0);
511
512 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
513 assert_eq!(decoded, npdu);
514 }
515
516 #[test]
517 fn source_only_round_trip() {
518 let npdu = Npdu {
519 source: Some(NpduAddress {
520 network: 500,
521 mac_address: MacAddr::from_slice(&[0x01]),
522 }),
523 payload: Bytes::from_static(&[0x30, 0x01, 0x0C]),
524 ..Default::default()
525 };
526 let encoded = encode_to_vec(&npdu);
527 assert_eq!(encoded[1] & 0x08, 0x08);
529 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
531 assert_eq!(decoded, npdu);
532 }
533
534 #[test]
535 fn source_and_destination_round_trip() {
536 let npdu = Npdu {
537 expecting_reply: true,
538 destination: Some(NpduAddress {
539 network: 2000,
540 mac_address: MacAddr::from_slice(&[0x0A, 0x00, 0x02, 0x01, 0xBA, 0xC0]),
541 }),
542 source: Some(NpduAddress {
543 network: 1000,
544 mac_address: MacAddr::from_slice(&[0x0A, 0x00, 0x01, 0x01, 0xBA, 0xC0]),
545 }),
546 hop_count: 250,
547 payload: Bytes::from_static(&[0x00, 0x05, 0x01, 0x0C]),
548 ..Default::default()
549 };
550 let encoded = encode_to_vec(&npdu);
551 assert_eq!(encoded[1], 0x2C);
553 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
554 assert_eq!(decoded, npdu);
555 }
556
557 #[test]
558 fn network_message_round_trip() {
559 let npdu = Npdu {
560 is_network_message: true,
561 message_type: Some(0x01), payload: Bytes::from_static(&[0x03, 0xE8]), ..Default::default()
564 };
565 let encoded = encode_to_vec(&npdu);
566 assert_eq!(encoded[1] & 0x80, 0x80);
568 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
569 assert_eq!(decoded, npdu);
570 }
571
572 #[test]
573 fn reject_message_to_network_payload_decodes_typed_reason_and_dnet() {
574 let decoded = decode_reject_message_to_network(&[
575 RejectMessageReason::MESSAGE_TOO_LONG.to_raw(),
576 0x12,
577 0x34,
578 ])
579 .unwrap();
580 assert_eq!(decoded.reason, RejectMessageReason::MESSAGE_TOO_LONG);
581 assert_eq!(decoded.dnet, 0x1234);
582 }
583
584 #[test]
585 fn reject_message_to_network_payload_requires_exact_length() {
586 for payload in [&[][..], &[4, 0][..], &[4, 0, 1, 2][..]] {
587 assert!(decode_reject_message_to_network(payload).is_err());
588 }
589 }
590
591 #[test]
592 fn proprietary_network_message_round_trip() {
593 let npdu = Npdu {
594 is_network_message: true,
595 message_type: Some(0x80), vendor_id: Some(999),
597 payload: Bytes::from_static(&[0xDE, 0xAD]),
598 ..Default::default()
599 };
600 let encoded = encode_to_vec(&npdu);
601 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
602 assert_eq!(decoded, npdu);
603 }
604
605 #[test]
606 fn wire_format_who_is_broadcast() {
607 let wire = [0x01, 0x20, 0xFF, 0xFF, 0x00, 0xFF, 0x10, 0x08];
611 let decoded = decode_npdu(Bytes::copy_from_slice(&wire)).unwrap();
612 assert!(!decoded.is_network_message);
613 assert!(!decoded.expecting_reply);
614 assert_eq!(decoded.priority, NetworkPriority::NORMAL);
615 assert_eq!(
616 decoded.destination,
617 Some(NpduAddress {
618 network: 0xFFFF,
619 mac_address: MacAddr::new(),
620 })
621 );
622 assert!(decoded.source.is_none());
623 assert_eq!(decoded.hop_count, 255);
624 assert_eq!(decoded.payload, vec![0x10, 0x08]);
625
626 let reencoded = encode_to_vec(&decoded);
628 assert_eq!(reencoded, wire);
629 }
630
631 #[test]
632 fn decode_too_short() {
633 assert!(decode_npdu(Bytes::new()).is_err());
634 assert!(decode_npdu(Bytes::from_static(&[0x01])).is_err());
635 }
636
637 #[test]
638 fn decode_wrong_version() {
639 assert!(decode_npdu(Bytes::from_static(&[0x02, 0x00])).is_err());
640 }
641
642 #[test]
643 fn decode_truncated_destination() {
644 assert!(decode_npdu(Bytes::from_static(&[0x01, 0x20, 0xFF])).is_err());
646 }
647
648 #[test]
649 fn decode_truncated_source() {
650 assert!(decode_npdu(Bytes::from_static(&[0x01, 0x08, 0x00])).is_err());
652 }
653
654 #[test]
657 fn npdu_network_zero() {
658 let npdu = Npdu {
660 destination: Some(NpduAddress {
661 network: 0,
662 mac_address: MacAddr::from_slice(&[0x01]),
663 }),
664 hop_count: 255,
665 payload: Bytes::from_static(&[0x10, 0x08]),
666 ..Default::default()
667 };
668 let mut buf = BytesMut::new();
669 let result = encode_npdu(&mut buf, &npdu);
670 assert!(result.is_err());
671 let err = format!("{}", result.unwrap_err());
672 assert!(err.contains("DNET"), "got: {err}");
673 }
674
675 #[test]
676 fn npdu_network_fffe() {
677 let npdu = Npdu {
680 destination: Some(NpduAddress {
681 network: 0xFFFE,
682 mac_address: MacAddr::from_slice(&[0x01, 0x02]),
683 }),
684 hop_count: 200,
685 payload: Bytes::from_static(&[0xAA]),
686 ..Default::default()
687 };
688 let encoded = encode_to_vec(&npdu);
689 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
690 assert_eq!(decoded.destination.as_ref().unwrap().network, 0xFFFE);
691 assert_eq!(decoded.hop_count, 200);
692 }
693
694 #[test]
695 fn npdu_hop_count_zero() {
696 let npdu = Npdu {
698 destination: Some(NpduAddress {
699 network: 1000,
700 mac_address: MacAddr::new(),
701 }),
702 hop_count: 0,
703 payload: Bytes::from_static(&[0x10, 0x08]),
704 ..Default::default()
705 };
706 let encoded = encode_to_vec(&npdu);
707 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
708 assert_eq!(decoded.hop_count, 0);
709 }
710
711 #[test]
712 fn npdu_source_with_empty_mac() {
713 let npdu = Npdu {
715 source: Some(NpduAddress {
716 network: 500,
717 mac_address: MacAddr::new(),
718 }),
719 payload: Bytes::from_static(&[0xBB]),
720 ..Default::default()
721 };
722 let mut buf = BytesMut::new();
723 let result = encode_npdu(&mut buf, &npdu);
724 assert!(result.is_err());
725 let err = format!("{}", result.unwrap_err());
726 assert!(err.contains("SLEN"), "got: {err}");
727 }
728
729 #[test]
730 fn npdu_destination_dlen_zero_broadcast_accepted() {
731 let npdu = Npdu {
733 destination: Some(NpduAddress {
734 network: 0xFFFF,
735 mac_address: MacAddr::new(),
736 }),
737 hop_count: 255,
738 payload: Bytes::from_static(&[0x10, 0x08]),
739 ..Default::default()
740 };
741 let encoded = encode_to_vec(&npdu);
742 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
743 assert_eq!(decoded.destination.as_ref().unwrap().network, 0xFFFF);
744 assert!(decoded.destination.as_ref().unwrap().mac_address.is_empty());
745 }
746
747 #[test]
748 fn npdu_destination_truncated_mac() {
749 let data = [0x01, 0x20, 0x03, 0xE8, 0x06, 0x01, 0x02];
752 assert!(decode_npdu(Bytes::copy_from_slice(&data)).is_err());
753 }
754
755 #[test]
756 fn npdu_source_truncated_mac() {
757 let data = [0x01, 0x08, 0x01, 0xF4, 0x04, 0x01]; assert!(decode_npdu(Bytes::copy_from_slice(&data)).is_err());
760 }
761
762 #[test]
763 fn npdu_missing_hop_count() {
764 let data = [0x01, 0x20, 0xFF, 0xFF, 0x00];
767 assert!(decode_npdu(Bytes::copy_from_slice(&data)).is_err());
768 }
769
770 #[test]
771 fn npdu_network_message_truncated_type() {
772 let data = [0x01, 0x80]; assert!(decode_npdu(Bytes::copy_from_slice(&data)).is_err());
775 }
776
777 #[test]
778 fn npdu_proprietary_message_truncated_vendor() {
779 let data = [0x01, 0x80, 0x80]; assert!(decode_npdu(Bytes::copy_from_slice(&data)).is_err());
782 }
783
784 #[test]
785 fn npdu_all_flags_round_trip() {
786 let npdu = Npdu {
788 is_network_message: false,
789 expecting_reply: true,
790 priority: NetworkPriority::LIFE_SAFETY,
791 destination: Some(NpduAddress {
792 network: 2000,
793 mac_address: MacAddr::from_slice(&[0x0A, 0x00, 0x02, 0x01, 0xBA, 0xC0]),
794 }),
795 source: Some(NpduAddress {
796 network: 1000,
797 mac_address: MacAddr::from_slice(&[0x0A, 0x00, 0x01, 0x01, 0xBA, 0xC0]),
798 }),
799 hop_count: 127,
800 payload: Bytes::from_static(&[0xDE, 0xAD, 0xBE, 0xEF]),
801 ..Default::default()
802 };
803 let encoded = encode_to_vec(&npdu);
804 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
805 assert_eq!(decoded, npdu);
806 }
807
808 #[test]
809 fn npdu_empty_payload() {
810 let npdu = Npdu {
812 payload: Bytes::new(),
813 ..Default::default()
814 };
815 let encoded = encode_to_vec(&npdu);
816 let decoded = decode_npdu(Bytes::from(encoded)).unwrap();
817 assert!(decoded.payload.is_empty());
818 }
819
820 #[test]
821 fn reject_snet_zero() {
822 let npdu = Npdu {
824 source: Some(NpduAddress {
825 network: 0,
826 mac_address: MacAddr::from_slice(&[0x01]),
827 }),
828 payload: Bytes::from_static(&[0x10, 0x08]),
829 ..Default::default()
830 };
831 let mut buf = BytesMut::new();
832 let result = encode_npdu(&mut buf, &npdu);
833 assert!(result.is_err());
834 let err = format!("{}", result.unwrap_err());
835 assert!(err.contains("SNET"), "got: {err}");
836 }
837
838 #[test]
839 fn reserved_bits_warning_still_decodes() {
840 let mut data = vec![0x01, 0x40]; data.extend_from_slice(&[0x10, 0x08]);
844
845 let result = decode_npdu(Bytes::copy_from_slice(&data));
847 assert!(
848 result.is_ok(),
849 "reserved bits should not cause decode failure"
850 );
851 }
852}