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