1use bacnet_types::enums::{
14 AbortReason, ConfirmedServiceChoice, ErrorClass, ErrorCode, PduType, RejectReason,
15 UnconfirmedServiceChoice,
16};
17use bacnet_types::error::Error;
18use bytes::{BufMut, Bytes, BytesMut};
19
20use crate::primitives;
21use crate::tags;
22
23const MAX_SEGMENTS_DECODE: [Option<u8>; 8] = [
30 None, Some(2), Some(4), Some(8), Some(16), Some(32), Some(64), Some(255), ];
39
40fn encode_max_segments(value: Option<u8>) -> u8 {
42 match value {
43 None => 0,
44 Some(2) => 1,
45 Some(4) => 2,
46 Some(8) => 3,
47 Some(16) => 4,
48 Some(32) => 5,
49 Some(64) => 6,
50 Some(_) => 7, }
52}
53
54fn decode_max_segments(value: u8) -> Option<u8> {
56 MAX_SEGMENTS_DECODE[(value & 0x07) as usize]
57}
58
59const MAX_APDU_DECODE: [u16; 6] = [50, 128, 206, 480, 1024, 1476];
65
66fn encode_max_apdu(value: u16) -> u8 {
68 match value {
69 50 => 0,
70 128 => 1,
71 206 => 2,
72 480 => 3,
73 1024 => 4,
74 _ => 5, }
76}
77
78fn decode_max_apdu(value: u8) -> u16 {
80 let idx = (value & 0x0F) as usize;
81 if idx < MAX_APDU_DECODE.len() {
82 MAX_APDU_DECODE[idx]
83 } else {
84 tracing::warn!(
85 value = idx,
86 "Reserved max-APDU-length field value, defaulting to 1476"
87 );
88 1476
89 }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
98pub struct ConfirmedRequest {
99 pub segmented: bool,
100 pub more_follows: bool,
101 pub segmented_response_accepted: bool,
102 pub max_segments: Option<u8>,
103 pub max_apdu_length: u16,
104 pub invoke_id: u8,
105 pub sequence_number: Option<u8>,
106 pub proposed_window_size: Option<u8>,
107 pub service_choice: ConfirmedServiceChoice,
108 pub service_request: Bytes,
109}
110
111#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct UnconfirmedRequest {
114 pub service_choice: UnconfirmedServiceChoice,
115 pub service_request: Bytes,
116}
117
118#[derive(Debug, Clone, PartialEq, Eq)]
120pub struct SimpleAck {
121 pub invoke_id: u8,
122 pub service_choice: ConfirmedServiceChoice,
123}
124
125#[derive(Debug, Clone, PartialEq, Eq)]
127pub struct ComplexAck {
128 pub segmented: bool,
129 pub more_follows: bool,
130 pub invoke_id: u8,
131 pub sequence_number: Option<u8>,
132 pub proposed_window_size: Option<u8>,
133 pub service_choice: ConfirmedServiceChoice,
134 pub service_ack: Bytes,
135}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct SegmentAck {
140 pub negative_ack: bool,
141 pub sent_by_server: bool,
142 pub invoke_id: u8,
143 pub sequence_number: u8,
144 pub actual_window_size: u8,
145}
146
147#[derive(Debug, Clone, PartialEq, Eq)]
149pub struct ErrorPdu {
150 pub invoke_id: u8,
151 pub service_choice: ConfirmedServiceChoice,
152 pub error_class: ErrorClass,
153 pub error_code: ErrorCode,
154 pub error_data: Bytes,
155}
156
157#[derive(Debug, Clone, PartialEq, Eq)]
159pub struct RejectPdu {
160 pub invoke_id: u8,
161 pub reject_reason: RejectReason,
162}
163
164#[derive(Debug, Clone, PartialEq, Eq)]
166pub struct AbortPdu {
167 pub sent_by_server: bool,
168 pub invoke_id: u8,
169 pub abort_reason: AbortReason,
170}
171
172#[derive(Debug, Clone, PartialEq, Eq)]
174pub enum Apdu {
175 ConfirmedRequest(ConfirmedRequest),
176 UnconfirmedRequest(UnconfirmedRequest),
177 SimpleAck(SimpleAck),
178 ComplexAck(ComplexAck),
179 SegmentAck(SegmentAck),
180 Error(ErrorPdu),
181 Reject(RejectPdu),
182 Abort(AbortPdu),
183}
184
185pub fn encode_apdu(buf: &mut BytesMut, apdu: &Apdu) {
191 match apdu {
192 Apdu::ConfirmedRequest(pdu) => encode_confirmed_request(buf, pdu),
193 Apdu::UnconfirmedRequest(pdu) => encode_unconfirmed_request(buf, pdu),
194 Apdu::SimpleAck(pdu) => encode_simple_ack(buf, pdu),
195 Apdu::ComplexAck(pdu) => encode_complex_ack(buf, pdu),
196 Apdu::SegmentAck(pdu) => encode_segment_ack(buf, pdu),
197 Apdu::Error(pdu) => encode_error(buf, pdu),
198 Apdu::Reject(pdu) => encode_reject(buf, pdu),
199 Apdu::Abort(pdu) => encode_abort(buf, pdu),
200 }
201}
202
203fn encode_confirmed_request(buf: &mut BytesMut, pdu: &ConfirmedRequest) {
204 let mut byte0 = PduType::CONFIRMED_REQUEST.to_raw() << 4;
205 if pdu.segmented {
206 byte0 |= 0x08;
207 }
208 if pdu.more_follows {
209 byte0 |= 0x04;
210 }
211 if pdu.segmented_response_accepted {
212 byte0 |= 0x02;
213 }
214 buf.put_u8(byte0);
215
216 let byte1 = (encode_max_segments(pdu.max_segments) << 4) | encode_max_apdu(pdu.max_apdu_length);
217 buf.put_u8(byte1);
218
219 buf.put_u8(pdu.invoke_id);
220
221 if pdu.segmented {
222 buf.put_u8(pdu.sequence_number.unwrap_or(0));
223 buf.put_u8(pdu.proposed_window_size.unwrap_or(1).clamp(1, 127));
224 }
225
226 buf.put_u8(pdu.service_choice.to_raw());
227 buf.put_slice(&pdu.service_request);
228}
229
230fn encode_unconfirmed_request(buf: &mut BytesMut, pdu: &UnconfirmedRequest) {
231 buf.put_u8(PduType::UNCONFIRMED_REQUEST.to_raw() << 4);
232 buf.put_u8(pdu.service_choice.to_raw());
233 buf.put_slice(&pdu.service_request);
234}
235
236fn encode_simple_ack(buf: &mut BytesMut, pdu: &SimpleAck) {
237 buf.put_u8(PduType::SIMPLE_ACK.to_raw() << 4);
238 buf.put_u8(pdu.invoke_id);
239 buf.put_u8(pdu.service_choice.to_raw());
240}
241
242fn encode_complex_ack(buf: &mut BytesMut, pdu: &ComplexAck) {
243 let mut byte0 = PduType::COMPLEX_ACK.to_raw() << 4;
244 if pdu.segmented {
245 byte0 |= 0x08;
246 }
247 if pdu.more_follows {
248 byte0 |= 0x04;
249 }
250 buf.put_u8(byte0);
251
252 buf.put_u8(pdu.invoke_id);
253
254 if pdu.segmented {
255 buf.put_u8(pdu.sequence_number.unwrap_or(0));
256 buf.put_u8(pdu.proposed_window_size.unwrap_or(1).clamp(1, 127));
257 }
258
259 buf.put_u8(pdu.service_choice.to_raw());
260 buf.put_slice(&pdu.service_ack);
261}
262
263fn encode_segment_ack(buf: &mut BytesMut, pdu: &SegmentAck) {
264 let mut byte0 = PduType::SEGMENT_ACK.to_raw() << 4;
265 if pdu.negative_ack {
266 byte0 |= 0x02;
267 }
268 if pdu.sent_by_server {
269 byte0 |= 0x01;
270 }
271 buf.put_u8(byte0);
272 buf.put_u8(pdu.invoke_id);
273 buf.put_u8(pdu.sequence_number);
274 buf.put_u8(pdu.actual_window_size.clamp(1, 127));
275}
276
277fn encode_error(buf: &mut BytesMut, pdu: &ErrorPdu) {
278 buf.put_u8(PduType::ERROR.to_raw() << 4);
279 buf.put_u8(pdu.invoke_id);
280 buf.put_u8(pdu.service_choice.to_raw());
281 primitives::encode_app_enumerated(buf, pdu.error_class.to_raw() as u32);
282 primitives::encode_app_enumerated(buf, pdu.error_code.to_raw() as u32);
283 if !pdu.error_data.is_empty() {
284 buf.put_slice(&pdu.error_data);
285 }
286}
287
288fn encode_reject(buf: &mut BytesMut, pdu: &RejectPdu) {
289 buf.put_u8(PduType::REJECT.to_raw() << 4);
290 buf.put_u8(pdu.invoke_id);
291 buf.put_u8(pdu.reject_reason.to_raw());
292}
293
294fn encode_abort(buf: &mut BytesMut, pdu: &AbortPdu) {
295 let mut byte0 = PduType::ABORT.to_raw() << 4;
296 if pdu.sent_by_server {
297 byte0 |= 0x01;
298 }
299 buf.put_u8(byte0);
300 buf.put_u8(pdu.invoke_id);
301 buf.put_u8(pdu.abort_reason.to_raw());
302}
303
304pub fn decode_apdu(data: Bytes) -> Result<Apdu, Error> {
310 if data.is_empty() {
311 return Err(Error::decoding(0, "APDU data is empty"));
312 }
313
314 let pdu_type_raw = (data[0] >> 4) & 0x0F;
315 let pdu_type = PduType::from_raw(pdu_type_raw);
316
317 if pdu_type == PduType::CONFIRMED_REQUEST {
318 decode_confirmed_request(data).map(Apdu::ConfirmedRequest)
319 } else if pdu_type == PduType::UNCONFIRMED_REQUEST {
320 decode_unconfirmed_request(data).map(Apdu::UnconfirmedRequest)
321 } else if pdu_type == PduType::SIMPLE_ACK {
322 decode_simple_ack(data).map(Apdu::SimpleAck)
323 } else if pdu_type == PduType::COMPLEX_ACK {
324 decode_complex_ack(data).map(Apdu::ComplexAck)
325 } else if pdu_type == PduType::SEGMENT_ACK {
326 decode_segment_ack(data).map(Apdu::SegmentAck)
327 } else if pdu_type == PduType::ERROR {
328 decode_error(data).map(Apdu::Error)
329 } else if pdu_type == PduType::REJECT {
330 decode_reject(data).map(Apdu::Reject)
331 } else if pdu_type == PduType::ABORT {
332 decode_abort(data).map(Apdu::Abort)
333 } else {
334 Err(Error::decoding(
335 0,
336 format!("unknown PDU type nibble: {:#x}", pdu_type_raw),
337 ))
338 }
339}
340
341fn decode_confirmed_request(data: Bytes) -> Result<ConfirmedRequest, Error> {
342 if data.len() < 4 {
343 return Err(Error::buffer_too_short(4, data.len()));
344 }
345
346 let byte0 = data[0];
347 let segmented = byte0 & 0x08 != 0;
348 let more_follows = byte0 & 0x04 != 0;
349 let segmented_response_accepted = byte0 & 0x02 != 0;
350
351 let byte1 = data[1];
352 let max_segments = decode_max_segments((byte1 >> 4) & 0x07);
353 let max_apdu_length = decode_max_apdu(byte1 & 0x0F);
354
355 let invoke_id = data[2];
356 let mut offset = 3;
357
358 let (sequence_number, proposed_window_size) = if segmented {
359 if data.len() < 6 {
360 return Err(Error::decoding(
361 offset,
362 "segmented ConfirmedRequest too short for sequence/window fields",
363 ));
364 }
365 let seq = data[offset];
366 let win = data[offset + 1];
367 offset += 2;
368 (Some(seq), Some(win))
369 } else {
370 (None, None)
371 };
372
373 if offset >= data.len() {
374 return Err(Error::decoding(
375 offset,
376 "ConfirmedRequest missing service choice",
377 ));
378 }
379 let service_choice = ConfirmedServiceChoice::from_raw(data[offset]);
380 offset += 1;
381
382 let service_request = data.slice(offset..);
383
384 Ok(ConfirmedRequest {
385 segmented,
386 more_follows,
387 segmented_response_accepted,
388 max_segments,
389 max_apdu_length,
390 invoke_id,
391 sequence_number,
392 proposed_window_size,
393 service_choice,
394 service_request,
395 })
396}
397
398fn decode_unconfirmed_request(data: Bytes) -> Result<UnconfirmedRequest, Error> {
399 if data.len() < 2 {
400 return Err(Error::buffer_too_short(2, data.len()));
401 }
402
403 let service_choice = UnconfirmedServiceChoice::from_raw(data[1]);
404 let service_request = data.slice(2..);
405
406 Ok(UnconfirmedRequest {
407 service_choice,
408 service_request,
409 })
410}
411
412fn decode_simple_ack(data: Bytes) -> Result<SimpleAck, Error> {
413 if data.len() < 3 {
414 return Err(Error::buffer_too_short(3, data.len()));
415 }
416
417 Ok(SimpleAck {
418 invoke_id: data[1],
419 service_choice: ConfirmedServiceChoice::from_raw(data[2]),
420 })
421}
422
423fn decode_complex_ack(data: Bytes) -> Result<ComplexAck, Error> {
424 if data.len() < 3 {
425 return Err(Error::buffer_too_short(3, data.len()));
426 }
427
428 let byte0 = data[0];
429 let segmented = byte0 & 0x08 != 0;
430 let more_follows = byte0 & 0x04 != 0;
431
432 let invoke_id = data[1];
433 let mut offset = 2;
434
435 let (sequence_number, proposed_window_size) = if segmented {
436 if data.len() < 5 {
437 return Err(Error::decoding(
438 offset,
439 "segmented ComplexAck too short for sequence/window fields",
440 ));
441 }
442 let seq = data[offset];
443 let win = data[offset + 1];
444 offset += 2;
445 (Some(seq), Some(win))
446 } else {
447 (None, None)
448 };
449
450 if offset >= data.len() {
451 return Err(Error::decoding(offset, "ComplexAck missing service choice"));
452 }
453 let service_choice = ConfirmedServiceChoice::from_raw(data[offset]);
454 offset += 1;
455
456 let service_ack = data.slice(offset..);
457
458 Ok(ComplexAck {
459 segmented,
460 more_follows,
461 invoke_id,
462 sequence_number,
463 proposed_window_size,
464 service_choice,
465 service_ack,
466 })
467}
468
469fn decode_segment_ack(data: Bytes) -> Result<SegmentAck, Error> {
470 if data.len() < 4 {
471 return Err(Error::buffer_too_short(4, data.len()));
472 }
473
474 let byte0 = data[0];
475 let raw_window = data[3];
476 if raw_window == 0 || raw_window > 127 {
477 tracing::warn!(
478 actual_window_size = raw_window,
479 "SegmentAck window size out of range (1-127), clamping"
480 );
481 }
482 Ok(SegmentAck {
483 negative_ack: byte0 & 0x02 != 0,
484 sent_by_server: byte0 & 0x01 != 0,
485 invoke_id: data[1],
486 sequence_number: data[2],
487 actual_window_size: raw_window.clamp(1, 127),
488 })
489}
490
491fn decode_error(data: Bytes) -> Result<ErrorPdu, Error> {
492 if data.len() < 5 {
493 return Err(Error::buffer_too_short(5, data.len()));
494 }
495
496 let invoke_id = data[1];
497 let service_choice = ConfirmedServiceChoice::from_raw(data[2]);
498
499 let mut offset = 3;
500 let (tag, tag_end) = tags::decode_tag(&data, offset)?;
501 if tag.class != tags::TagClass::Application || tag.number != tags::app_tag::ENUMERATED {
502 return Err(Error::decoding(
503 offset,
504 "ErrorPDU error class: expected application-tagged enumerated",
505 ));
506 }
507 let class_end = tag_end
508 .checked_add(tag.length as usize)
509 .ok_or_else(|| Error::decoding(tag_end, "ErrorPDU error class length overflow"))?;
510 if class_end > data.len() {
511 return Err(Error::decoding(
512 tag_end,
513 "ErrorPDU truncated at error class",
514 ));
515 }
516 let error_class_raw = primitives::decode_unsigned(&data[tag_end..class_end])? as u16;
517 offset = class_end;
518
519 let (tag, tag_end) = tags::decode_tag(&data, offset)?;
520 if tag.class != tags::TagClass::Application || tag.number != tags::app_tag::ENUMERATED {
521 return Err(Error::decoding(
522 offset,
523 "ErrorPDU error code: expected application-tagged enumerated",
524 ));
525 }
526 let code_end = tag_end
527 .checked_add(tag.length as usize)
528 .ok_or_else(|| Error::decoding(tag_end, "ErrorPDU error code length overflow"))?;
529 if code_end > data.len() {
530 return Err(Error::decoding(tag_end, "ErrorPDU truncated at error code"));
531 }
532 let error_code_raw = primitives::decode_unsigned(&data[tag_end..code_end])? as u16;
533 offset = code_end;
534
535 let error_data = if offset < data.len() {
536 data.slice(offset..)
537 } else {
538 Bytes::new()
539 };
540
541 Ok(ErrorPdu {
542 invoke_id,
543 service_choice,
544 error_class: ErrorClass::from_raw(error_class_raw),
545 error_code: ErrorCode::from_raw(error_code_raw),
546 error_data,
547 })
548}
549
550fn decode_reject(data: Bytes) -> Result<RejectPdu, Error> {
551 if data.len() < 3 {
552 return Err(Error::buffer_too_short(3, data.len()));
553 }
554
555 Ok(RejectPdu {
556 invoke_id: data[1],
557 reject_reason: RejectReason::from_raw(data[2]),
558 })
559}
560
561fn decode_abort(data: Bytes) -> Result<AbortPdu, Error> {
562 if data.len() < 3 {
563 return Err(Error::buffer_too_short(3, data.len()));
564 }
565
566 let byte0 = data[0];
567 Ok(AbortPdu {
568 sent_by_server: byte0 & 0x01 != 0,
569 invoke_id: data[1],
570 abort_reason: AbortReason::from_raw(data[2]),
571 })
572}
573
574#[cfg(test)]
579mod tests {
580 use super::*;
581
582 fn encode_to_vec(apdu: &Apdu) -> Vec<u8> {
583 let mut buf = BytesMut::with_capacity(64);
584 encode_apdu(&mut buf, apdu);
585 buf.to_vec()
586 }
587
588 #[test]
591 fn max_segments_round_trip() {
592 assert_eq!(decode_max_segments(encode_max_segments(None)), None);
593 assert_eq!(decode_max_segments(encode_max_segments(Some(2))), Some(2));
594 assert_eq!(decode_max_segments(encode_max_segments(Some(4))), Some(4));
595 assert_eq!(decode_max_segments(encode_max_segments(Some(8))), Some(8));
596 assert_eq!(decode_max_segments(encode_max_segments(Some(16))), Some(16));
597 assert_eq!(decode_max_segments(encode_max_segments(Some(32))), Some(32));
598 assert_eq!(decode_max_segments(encode_max_segments(Some(64))), Some(64));
599 assert_eq!(
600 decode_max_segments(encode_max_segments(Some(100))),
601 Some(255)
602 );
603 }
604
605 #[test]
606 fn max_apdu_round_trip() {
607 assert_eq!(decode_max_apdu(encode_max_apdu(50)), 50);
608 assert_eq!(decode_max_apdu(encode_max_apdu(128)), 128);
609 assert_eq!(decode_max_apdu(encode_max_apdu(206)), 206);
610 assert_eq!(decode_max_apdu(encode_max_apdu(480)), 480);
611 assert_eq!(decode_max_apdu(encode_max_apdu(1024)), 1024);
612 assert_eq!(decode_max_apdu(encode_max_apdu(1476)), 1476);
613 assert_eq!(decode_max_apdu(encode_max_apdu(9999)), 1476);
615 }
616
617 #[test]
620 fn confirmed_request_non_segmented_round_trip() {
621 let pdu = ConfirmedRequest {
622 segmented: false,
623 more_follows: false,
624 segmented_response_accepted: true,
625 max_segments: Some(4),
626 max_apdu_length: 1476,
627 invoke_id: 42,
628 sequence_number: None,
629 proposed_window_size: None,
630 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
631 service_request: Bytes::from_static(&[0x0C, 0x02, 0x00, 0x00, 0x01]),
632 };
633 let apdu = Apdu::ConfirmedRequest(pdu);
634 let encoded = encode_to_vec(&apdu);
635 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
636 assert_eq!(apdu, decoded);
637 }
638
639 #[test]
640 fn confirmed_request_segmented_round_trip() {
641 let pdu = ConfirmedRequest {
642 segmented: true,
643 more_follows: true,
644 segmented_response_accepted: true,
645 max_segments: Some(64),
646 max_apdu_length: 480,
647 invoke_id: 7,
648 sequence_number: Some(3),
649 proposed_window_size: Some(16),
650 service_choice: ConfirmedServiceChoice::WRITE_PROPERTY,
651 service_request: Bytes::from_static(&[0xAA, 0xBB]),
652 };
653 let apdu = Apdu::ConfirmedRequest(pdu);
654 let encoded = encode_to_vec(&apdu);
655 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
656 assert_eq!(apdu, decoded);
657 }
658
659 #[test]
660 fn confirmed_request_wire_format() {
661 let pdu = ConfirmedRequest {
662 segmented: false,
663 more_follows: false,
664 segmented_response_accepted: false,
665 max_segments: None,
666 max_apdu_length: 1476,
667 invoke_id: 1,
668 sequence_number: None,
669 proposed_window_size: None,
670 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
671 service_request: Bytes::new(),
672 };
673 let encoded = encode_to_vec(&Apdu::ConfirmedRequest(pdu));
674 assert_eq!(&encoded[..4], &[0x00, 0x05, 0x01, 0x0C]);
679 }
680
681 #[test]
684 fn unconfirmed_request_round_trip() {
685 let pdu = UnconfirmedRequest {
686 service_choice: UnconfirmedServiceChoice::WHO_IS,
687 service_request: Bytes::from_static(&[0x01, 0x02, 0x03]),
688 };
689 let apdu = Apdu::UnconfirmedRequest(pdu);
690 let encoded = encode_to_vec(&apdu);
691 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
692 assert_eq!(apdu, decoded);
693 }
694
695 #[test]
696 fn unconfirmed_request_wire_format() {
697 let pdu = UnconfirmedRequest {
698 service_choice: UnconfirmedServiceChoice::I_AM,
699 service_request: Bytes::new(),
700 };
701 let encoded = encode_to_vec(&Apdu::UnconfirmedRequest(pdu));
702 assert_eq!(encoded, vec![0x10, 0x00]);
705 }
706
707 #[test]
710 fn simple_ack_round_trip() {
711 let pdu = SimpleAck {
712 invoke_id: 99,
713 service_choice: ConfirmedServiceChoice::WRITE_PROPERTY,
714 };
715 let apdu = Apdu::SimpleAck(pdu);
716 let encoded = encode_to_vec(&apdu);
717 assert_eq!(encoded.len(), 3);
718 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
719 assert_eq!(apdu, decoded);
720 }
721
722 #[test]
723 fn simple_ack_wire_format() {
724 let pdu = SimpleAck {
725 invoke_id: 5,
726 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
727 };
728 let encoded = encode_to_vec(&Apdu::SimpleAck(pdu));
729 assert_eq!(encoded, vec![0x20, 0x05, 0x0C]);
731 }
732
733 #[test]
736 fn complex_ack_non_segmented_round_trip() {
737 let pdu = ComplexAck {
738 segmented: false,
739 more_follows: false,
740 invoke_id: 42,
741 sequence_number: None,
742 proposed_window_size: None,
743 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
744 service_ack: Bytes::from_static(&[0xDE, 0xAD]),
745 };
746 let apdu = Apdu::ComplexAck(pdu);
747 let encoded = encode_to_vec(&apdu);
748 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
749 assert_eq!(apdu, decoded);
750 }
751
752 #[test]
753 fn complex_ack_segmented_round_trip() {
754 let pdu = ComplexAck {
755 segmented: true,
756 more_follows: false,
757 invoke_id: 10,
758 sequence_number: Some(5),
759 proposed_window_size: Some(8),
760 service_choice: ConfirmedServiceChoice::READ_PROPERTY_MULTIPLE,
761 service_ack: Bytes::from_static(&[0x01]),
762 };
763 let apdu = Apdu::ComplexAck(pdu);
764 let encoded = encode_to_vec(&apdu);
765 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
766 assert_eq!(apdu, decoded);
767 }
768
769 #[test]
772 fn segment_ack_round_trip() {
773 let pdu = SegmentAck {
774 negative_ack: true,
775 sent_by_server: false,
776 invoke_id: 55,
777 sequence_number: 12,
778 actual_window_size: 4,
779 };
780 let apdu = Apdu::SegmentAck(pdu);
781 let encoded = encode_to_vec(&apdu);
782 assert_eq!(encoded.len(), 4);
783 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
784 assert_eq!(apdu, decoded);
785 }
786
787 #[test]
788 fn segment_ack_flags() {
789 let pdu = SegmentAck {
791 negative_ack: true,
792 sent_by_server: true,
793 invoke_id: 1,
794 sequence_number: 0,
795 actual_window_size: 1,
796 };
797 let encoded = encode_to_vec(&Apdu::SegmentAck(pdu));
798 assert_eq!(encoded[0], 0x43);
800 }
801
802 #[test]
805 fn error_round_trip() {
806 let pdu = ErrorPdu {
807 invoke_id: 10,
808 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
809 error_class: ErrorClass::PROPERTY,
810 error_code: ErrorCode::UNKNOWN_PROPERTY,
811 error_data: Bytes::new(),
812 };
813 let apdu = Apdu::Error(pdu);
814 let encoded = encode_to_vec(&apdu);
815 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
816 assert_eq!(apdu, decoded);
817 }
818
819 #[test]
820 fn error_with_trailing_data_round_trip() {
821 let pdu = ErrorPdu {
822 invoke_id: 20,
823 service_choice: ConfirmedServiceChoice::CREATE_OBJECT,
824 error_class: ErrorClass::OBJECT,
825 error_code: ErrorCode::NO_OBJECTS_OF_SPECIFIED_TYPE,
826 error_data: Bytes::from_static(&[0x01, 0x02, 0x03]),
827 };
828 let apdu = Apdu::Error(pdu);
829 let encoded = encode_to_vec(&apdu);
830 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
831 assert_eq!(apdu, decoded);
832 }
833
834 #[test]
837 fn reject_round_trip() {
838 let pdu = RejectPdu {
839 invoke_id: 77,
840 reject_reason: RejectReason::INVALID_TAG,
841 };
842 let apdu = Apdu::Reject(pdu);
843 let encoded = encode_to_vec(&apdu);
844 assert_eq!(encoded.len(), 3);
845 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
846 assert_eq!(apdu, decoded);
847 }
848
849 #[test]
852 fn abort_round_trip() {
853 let pdu = AbortPdu {
854 sent_by_server: true,
855 invoke_id: 33,
856 abort_reason: AbortReason::BUFFER_OVERFLOW,
857 };
858 let apdu = Apdu::Abort(pdu);
859 let encoded = encode_to_vec(&apdu);
860 assert_eq!(encoded.len(), 3);
861 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
862 assert_eq!(apdu, decoded);
863 }
864
865 #[test]
866 fn abort_server_flag() {
867 let pdu = AbortPdu {
868 sent_by_server: true,
869 invoke_id: 0,
870 abort_reason: AbortReason::OTHER,
871 };
872 let encoded = encode_to_vec(&Apdu::Abort(pdu));
873 assert_eq!(encoded[0], 0x71);
875
876 let pdu = AbortPdu {
877 sent_by_server: false,
878 invoke_id: 0,
879 abort_reason: AbortReason::OTHER,
880 };
881 let encoded = encode_to_vec(&Apdu::Abort(pdu));
882 assert_eq!(encoded[0], 0x70);
884 }
885
886 #[test]
889 fn decode_empty_data() {
890 assert!(decode_apdu(Bytes::new()).is_err());
891 }
892
893 #[test]
894 fn decode_unknown_pdu_type() {
895 assert!(decode_apdu(Bytes::from_static(&[0xF0])).is_err());
897 }
898
899 #[test]
900 fn decode_truncated_confirmed_request() {
901 assert!(decode_apdu(Bytes::from_static(&[0x00, 0x05])).is_err());
903 }
904
905 #[test]
906 fn decode_truncated_simple_ack() {
907 assert!(decode_apdu(Bytes::from_static(&[0x20, 0x01])).is_err());
909 }
910
911 #[test]
914 fn decode_truncated_segmented_confirmed_request() {
915 assert!(decode_apdu(Bytes::from_static(&[0x08, 0x05, 0x01])).is_err());
921 }
922
923 #[test]
924 fn decode_segmented_confirmed_request_missing_service() {
925 assert!(decode_apdu(Bytes::from_static(&[0x08, 0x05, 0x01, 0x00, 0x01])).is_err());
928 }
929
930 #[test]
931 fn decode_truncated_segmented_complex_ack() {
932 assert!(decode_apdu(Bytes::from_static(&[0x38, 0x01])).is_err());
937 }
938
939 #[test]
940 fn decode_complex_ack_missing_service_choice() {
941 assert!(decode_apdu(Bytes::from_static(&[0x30, 0x01])).is_err());
943 }
944
945 #[test]
946 fn decode_truncated_segment_ack() {
947 assert!(decode_apdu(Bytes::from_static(&[0x40, 0x01, 0x02])).is_err());
949 }
950
951 #[test]
952 fn decode_truncated_error_pdu() {
953 assert!(decode_apdu(Bytes::from_static(&[0x50, 0x01, 0x0C, 0x91])).is_err());
955 }
956
957 #[test]
958 fn decode_truncated_reject() {
959 assert!(decode_apdu(Bytes::from_static(&[0x60, 0x01])).is_err());
961 }
962
963 #[test]
964 fn decode_truncated_abort() {
965 assert!(decode_apdu(Bytes::from_static(&[0x70, 0x01])).is_err());
967 }
968
969 #[test]
972 fn confirmed_request_empty_service_data() {
973 let pdu = ConfirmedRequest {
974 segmented: false,
975 more_follows: false,
976 segmented_response_accepted: false,
977 max_segments: None,
978 max_apdu_length: 1476,
979 invoke_id: 0,
980 sequence_number: None,
981 proposed_window_size: None,
982 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
983 service_request: Bytes::new(),
984 };
985 let apdu = Apdu::ConfirmedRequest(pdu);
986 let encoded = encode_to_vec(&apdu);
987 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
988 assert_eq!(apdu, decoded);
989 }
990
991 #[test]
992 fn confirmed_request_invoke_id_zero() {
993 let pdu = ConfirmedRequest {
994 segmented: false,
995 more_follows: false,
996 segmented_response_accepted: true,
997 max_segments: Some(64),
998 max_apdu_length: 1476,
999 invoke_id: 0,
1000 sequence_number: None,
1001 proposed_window_size: None,
1002 service_choice: ConfirmedServiceChoice::WRITE_PROPERTY,
1003 service_request: Bytes::from_static(&[0xAA]),
1004 };
1005 let apdu = Apdu::ConfirmedRequest(pdu);
1006 let encoded = encode_to_vec(&apdu);
1007 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
1008 assert_eq!(apdu, decoded);
1009 }
1010
1011 #[test]
1012 fn confirmed_request_invoke_id_255() {
1013 let pdu = ConfirmedRequest {
1014 segmented: false,
1015 more_follows: false,
1016 segmented_response_accepted: true,
1017 max_segments: None,
1018 max_apdu_length: 480,
1019 invoke_id: 255,
1020 sequence_number: None,
1021 proposed_window_size: None,
1022 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
1023 service_request: Bytes::from_static(&[0x01]),
1024 };
1025 let apdu = Apdu::ConfirmedRequest(pdu);
1026 let encoded = encode_to_vec(&apdu);
1027 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
1028 assert_eq!(apdu, decoded);
1029 }
1030
1031 #[test]
1032 fn segmented_request_sequence_zero() {
1033 let pdu = ConfirmedRequest {
1034 segmented: true,
1035 more_follows: true,
1036 segmented_response_accepted: true,
1037 max_segments: Some(64),
1038 max_apdu_length: 480,
1039 invoke_id: 5,
1040 sequence_number: Some(0),
1041 proposed_window_size: Some(1),
1042 service_choice: ConfirmedServiceChoice::READ_PROPERTY_MULTIPLE,
1043 service_request: Bytes::from_static(&[0x01, 0x02]),
1044 };
1045 let apdu = Apdu::ConfirmedRequest(pdu);
1046 let encoded = encode_to_vec(&apdu);
1047 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
1048 assert_eq!(apdu, decoded);
1049 }
1050
1051 #[test]
1052 fn error_pdu_truncated_error_class() {
1053 assert!(decode_apdu(Bytes::from_static(&[0x50, 0x01, 0x0C])).is_err());
1056 }
1057
1058 #[test]
1059 fn error_pdu_truncated_error_code() {
1060 let mut buf = BytesMut::with_capacity(16);
1063 buf.put_u8(0x50); buf.put_u8(1); buf.put_u8(0x0C); primitives::encode_app_enumerated(&mut buf, 2); assert!(decode_apdu(buf.freeze()).is_err());
1068 }
1069
1070 #[test]
1071 fn unconfirmed_request_empty_service_data() {
1072 let pdu = UnconfirmedRequest {
1073 service_choice: UnconfirmedServiceChoice::WHO_IS,
1074 service_request: Bytes::new(),
1075 };
1076 let apdu = Apdu::UnconfirmedRequest(pdu);
1077 let encoded = encode_to_vec(&apdu);
1078 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
1079 assert_eq!(apdu, decoded);
1080 }
1081}