ironrdp_dvc/
pdu.rs

1use alloc::format;
2use core::fmt;
3
4use ironrdp_core::{
5    cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, unsupported_value_err, Decode, DecodeError,
6    DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor,
7};
8use ironrdp_pdu::utils::{
9    checked_sum, encoded_str_len, read_string_from_cursor, strict_sum, write_string_to_cursor, CharacterSet,
10};
11use ironrdp_svc::SvcEncode;
12
13use crate::{DynamicChannelId, String, Vec};
14
15/// Dynamic Virtual Channel PDU's that are sent by both client and server.
16#[derive(Debug, PartialEq)]
17pub enum DrdynvcDataPdu {
18    DataFirst(DataFirstPdu),
19    Data(DataPdu),
20}
21
22impl DrdynvcDataPdu {
23    /// Maximum size of the `data` field in `DrdynvcDataPdu`.
24    pub const MAX_DATA_SIZE: usize = 1590;
25
26    pub fn channel_id(&self) -> DynamicChannelId {
27        match self {
28            DrdynvcDataPdu::DataFirst(pdu) => pdu.channel_id,
29            DrdynvcDataPdu::Data(pdu) => pdu.channel_id,
30        }
31    }
32}
33
34impl Encode for DrdynvcDataPdu {
35    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
36        match self {
37            DrdynvcDataPdu::DataFirst(pdu) => pdu.encode(dst),
38            DrdynvcDataPdu::Data(pdu) => pdu.encode(dst),
39        }
40    }
41
42    fn name(&self) -> &'static str {
43        match self {
44            DrdynvcDataPdu::DataFirst(_) => DataFirstPdu::name(),
45            DrdynvcDataPdu::Data(_) => DataPdu::name(),
46        }
47    }
48
49    fn size(&self) -> usize {
50        match self {
51            DrdynvcDataPdu::DataFirst(pdu) => pdu.size(),
52            DrdynvcDataPdu::Data(pdu) => pdu.size(),
53        }
54    }
55}
56
57/// Dynamic Virtual Channel PDU's that are sent by the client.
58#[derive(Debug, PartialEq)]
59pub enum DrdynvcClientPdu {
60    Capabilities(CapabilitiesResponsePdu),
61    Create(CreateResponsePdu),
62    Close(ClosePdu),
63    Data(DrdynvcDataPdu),
64}
65
66impl Encode for DrdynvcClientPdu {
67    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
68        match self {
69            DrdynvcClientPdu::Capabilities(pdu) => pdu.encode(dst),
70            DrdynvcClientPdu::Create(pdu) => pdu.encode(dst),
71            DrdynvcClientPdu::Data(pdu) => pdu.encode(dst),
72            DrdynvcClientPdu::Close(pdu) => pdu.encode(dst),
73        }
74    }
75
76    fn name(&self) -> &'static str {
77        match self {
78            DrdynvcClientPdu::Capabilities(_) => CapabilitiesResponsePdu::name(),
79            DrdynvcClientPdu::Create(_) => CreateResponsePdu::name(),
80            DrdynvcClientPdu::Data(pdu) => pdu.name(),
81            DrdynvcClientPdu::Close(_) => ClosePdu::name(),
82        }
83    }
84
85    fn size(&self) -> usize {
86        match self {
87            DrdynvcClientPdu::Capabilities(_) => CapabilitiesResponsePdu::size(),
88            DrdynvcClientPdu::Create(pdu) => pdu.size(),
89            DrdynvcClientPdu::Data(pdu) => pdu.size(),
90            DrdynvcClientPdu::Close(pdu) => pdu.size(),
91        }
92    }
93}
94
95impl Decode<'_> for DrdynvcClientPdu {
96    fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
97        let header = Header::decode(src)?;
98        match header.cmd {
99            Cmd::Create => Ok(Self::Create(CreateResponsePdu::decode(header, src)?)),
100            Cmd::DataFirst => Ok(Self::Data(DrdynvcDataPdu::DataFirst(DataFirstPdu::decode(
101                header, src,
102            )?))),
103            Cmd::Data => Ok(Self::Data(DrdynvcDataPdu::Data(DataPdu::decode(header, src)?))),
104            Cmd::Close => Ok(Self::Close(ClosePdu::decode(header, src)?)),
105            Cmd::Capability => Ok(Self::Capabilities(CapabilitiesResponsePdu::decode(header, src)?)),
106            _ => Err(unsupported_value_err!("Cmd", header.cmd.into())),
107        }
108    }
109}
110
111/// Dynamic Virtual Channel PDU's that are sent by the server.
112#[derive(Debug, PartialEq)]
113pub enum DrdynvcServerPdu {
114    Capabilities(CapabilitiesRequestPdu),
115    Create(CreateRequestPdu),
116    Close(ClosePdu),
117    Data(DrdynvcDataPdu),
118}
119
120impl Encode for DrdynvcServerPdu {
121    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
122        match self {
123            DrdynvcServerPdu::Data(pdu) => pdu.encode(dst),
124            DrdynvcServerPdu::Capabilities(pdu) => pdu.encode(dst),
125            DrdynvcServerPdu::Create(pdu) => pdu.encode(dst),
126            DrdynvcServerPdu::Close(pdu) => pdu.encode(dst),
127        }
128    }
129
130    fn name(&self) -> &'static str {
131        match self {
132            DrdynvcServerPdu::Data(pdu) => pdu.name(),
133            DrdynvcServerPdu::Capabilities(pdu) => pdu.name(),
134            DrdynvcServerPdu::Create(_) => CreateRequestPdu::name(),
135            DrdynvcServerPdu::Close(_) => ClosePdu::name(),
136        }
137    }
138
139    fn size(&self) -> usize {
140        match self {
141            DrdynvcServerPdu::Data(pdu) => pdu.size(),
142            DrdynvcServerPdu::Capabilities(pdu) => pdu.size(),
143            DrdynvcServerPdu::Create(pdu) => pdu.size(),
144            DrdynvcServerPdu::Close(pdu) => pdu.size(),
145        }
146    }
147}
148
149impl Decode<'_> for DrdynvcServerPdu {
150    fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
151        let header = Header::decode(src)?;
152        match header.cmd {
153            Cmd::Create => Ok(Self::Create(CreateRequestPdu::decode(header, src)?)),
154            Cmd::DataFirst => Ok(Self::Data(DrdynvcDataPdu::DataFirst(DataFirstPdu::decode(
155                header, src,
156            )?))),
157            Cmd::Data => Ok(Self::Data(DrdynvcDataPdu::Data(DataPdu::decode(header, src)?))),
158            Cmd::Close => Ok(Self::Close(ClosePdu::decode(header, src)?)),
159            Cmd::Capability => Ok(Self::Capabilities(CapabilitiesRequestPdu::decode(header, src)?)),
160            _ => Err(unsupported_value_err!("Cmd", header.cmd.into())),
161        }
162    }
163}
164
165// Dynamic virtual channel PDU's are sent over a static virtual channel, so they are `SvcEncode`.
166impl SvcEncode for DrdynvcDataPdu {}
167impl SvcEncode for DrdynvcClientPdu {}
168impl SvcEncode for DrdynvcServerPdu {}
169
170/// [2.2] Message Syntax
171///
172/// [2.2]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedyc/0b07a750-bf51-4042-bcf2-a991b6729d6e
173#[derive(Debug, PartialEq)]
174pub struct Header {
175    cb_id: FieldType, // 2 bit
176    sp: FieldType,    // 2 bit; meaning depends on the cmd field
177    cmd: Cmd,         // 4 bit
178}
179
180impl Header {
181    pub const FIXED_PART_SIZE: usize = 1;
182    /// Create a new `Header` with the given `cb_id_val`, `sp_val`, and `cmd`.
183    ///
184    /// If `cb_id_val` or `sp_val` is not relevant for a given `cmd`, it should be set to 0 respectively.
185    fn new(cb_id_val: u32, sp_val: u32, cmd: Cmd) -> Self {
186        Self {
187            cb_id: FieldType::for_val(cb_id_val),
188            sp: FieldType::for_val(sp_val),
189            cmd,
190        }
191    }
192
193    fn with_cb_id(self, cb_id: FieldType) -> Self {
194        Self { cb_id, ..self }
195    }
196
197    fn with_sp(self, sp: FieldType) -> Self {
198        Self { sp, ..self }
199    }
200
201    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
202        ensure_fixed_part_size!(in: dst);
203        dst.write_u8(((self.cmd as u8) << 4) | (Into::<u8>::into(self.sp) << 2) | Into::<u8>::into(self.cb_id));
204        Ok(())
205    }
206
207    fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
208        ensure_size!(in: src, size: Self::size());
209        let byte = src.read_u8();
210        let cmd = Cmd::try_from(byte >> 4)?;
211        let sp = FieldType::from((byte >> 2) & 0b11);
212        let cb_id = FieldType::from(byte & 0b11);
213        Ok(Self { cb_id, sp, cmd })
214    }
215
216    fn size() -> usize {
217        Self::FIXED_PART_SIZE
218    }
219}
220
221/// [2.2] Message Syntax
222///
223/// [2.2]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedyc/0b07a750-bf51-4042-bcf2-a991b6729d6e
224#[repr(u8)]
225#[derive(Debug, Copy, Clone, PartialEq)]
226enum Cmd {
227    Create = 0x01,
228    DataFirst = 0x02,
229    Data = 0x03,
230    Close = 0x04,
231    Capability = 0x05,
232    DataFirstCompressed = 0x06,
233    DataCompressed = 0x07,
234    SoftSyncRequest = 0x08,
235    SoftSyncResponse = 0x09,
236}
237
238impl TryFrom<u8> for Cmd {
239    type Error = DecodeError;
240
241    fn try_from(byte: u8) -> Result<Self, Self::Error> {
242        match byte {
243            0x01 => Ok(Self::Create),
244            0x02 => Ok(Self::DataFirst),
245            0x03 => Ok(Self::Data),
246            0x04 => Ok(Self::Close),
247            0x05 => Ok(Self::Capability),
248            0x06 => Ok(Self::DataFirstCompressed),
249            0x07 => Ok(Self::DataCompressed),
250            0x08 => Ok(Self::SoftSyncRequest),
251            0x09 => Ok(Self::SoftSyncResponse),
252            _ => Err(invalid_field_err!("Cmd", "invalid cmd")),
253        }
254    }
255}
256
257impl fmt::Display for Cmd {
258    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259        f.write_str(match self {
260            Cmd::Create => "Create",
261            Cmd::DataFirst => "DataFirst",
262            Cmd::Data => "Data",
263            Cmd::Close => "Close",
264            Cmd::Capability => "Capability",
265            Cmd::DataFirstCompressed => "DataFirstCompressed",
266            Cmd::DataCompressed => "DataCompressed",
267            Cmd::SoftSyncRequest => "SoftSyncRequest",
268            Cmd::SoftSyncResponse => "SoftSyncResponse",
269        })
270    }
271}
272
273impl From<Cmd> for String {
274    fn from(cmd: Cmd) -> Self {
275        format!("{cmd:?}")
276    }
277}
278
279/// 2.2.3.1 DVC Data First PDU (DYNVC_DATA_FIRST)
280///
281/// [2.2.3.1]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedyc/69377767-56a6-4ab8-996b-7758676e9261
282#[derive(Debug, PartialEq)]
283pub struct DataFirstPdu {
284    header: Header,
285    pub channel_id: DynamicChannelId,
286    /// Length is the *total* length of the data to be sent, including the length
287    /// of the data that will be sent by subsequent DVC_DATA PDUs.
288    pub length: u32,
289    /// Data is just the data to be sent in this PDU.
290    pub data: Vec<u8>,
291}
292
293impl DataFirstPdu {
294    /// Create a new `DataFirstPdu` with the given `channel_id`, `length`, and `data`.
295    ///
296    /// `length` is the *total* length of the data to be sent, including the length
297    /// of the data that will be sent by subsequent `DataPdu`s.
298    ///
299    /// `data` is just the data to be sent in this PDU.
300    pub fn new(channel_id: DynamicChannelId, total_length: u32, data: Vec<u8>) -> Self {
301        Self {
302            header: Header::new(channel_id, total_length, Cmd::DataFirst),
303            channel_id,
304            length: total_length,
305            data,
306        }
307    }
308
309    #[must_use]
310    pub fn with_cb_id_type(self, cb_id: FieldType) -> Self {
311        Self {
312            header: self.header.with_cb_id(cb_id),
313            ..self
314        }
315    }
316
317    #[must_use]
318    pub fn with_sp_type(self, sp: FieldType) -> Self {
319        Self {
320            header: self.header.with_sp(sp),
321            ..self
322        }
323    }
324
325    fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
326        let fixed_part_size = checked_sum(&[header.cb_id.size_of_val(), header.sp.size_of_val()])?;
327        ensure_size!(in: src, size: fixed_part_size);
328        let channel_id = header.cb_id.decode_val(src)?;
329        let length = header.sp.decode_val(src)?;
330        let data = src.read_remaining().to_vec();
331        Ok(Self {
332            header,
333            channel_id,
334            length,
335            data,
336        })
337    }
338
339    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
340        ensure_size!(in: dst, size: self.size());
341        self.header.encode(dst)?;
342        self.header.cb_id.encode_val(self.channel_id, dst)?;
343        self.header
344            .sp
345            .encode_val(cast_length!("DataFirstPdu::Length", self.length)?, dst)?;
346        dst.write_slice(&self.data);
347        Ok(())
348    }
349
350    fn name() -> &'static str {
351        "DYNVC_DATA_FIRST"
352    }
353
354    fn size(&self) -> usize {
355        strict_sum(&[
356            Header::size(),
357            self.header.cb_id.size_of_val(),
358            self.header.sp.size_of_val(),
359            self.data.len(),
360        ])
361    }
362}
363
364#[derive(Debug, Copy, Clone, PartialEq, Eq)]
365pub struct FieldType(u8);
366
367impl FieldType {
368    pub const U8: Self = Self(0x00);
369    pub const U16: Self = Self(0x01);
370    pub const U32: Self = Self(0x02);
371
372    fn encode_val(&self, value: u32, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
373        ensure_size!(in: dst, size: self.size_of_val());
374        match *self {
375            FieldType::U8 => dst.write_u8(cast_length!("FieldType::encode", value)?),
376            FieldType::U16 => dst.write_u16(cast_length!("FieldType::encode", value)?),
377            FieldType::U32 => dst.write_u32(value),
378            _ => return Err(invalid_field_err!("FieldType", "invalid field type")),
379        };
380        Ok(())
381    }
382
383    fn decode_val(&self, src: &mut ReadCursor<'_>) -> DecodeResult<u32> {
384        ensure_size!(in: src, size: self.size_of_val());
385        match *self {
386            FieldType::U8 => Ok(u32::from(src.read_u8())),
387            FieldType::U16 => Ok(u32::from(src.read_u16())),
388            FieldType::U32 => Ok(src.read_u32()),
389            _ => Err(invalid_field_err!("FieldType", "invalid field type")),
390        }
391    }
392
393    /// Returns the size of the value in bytes.
394    fn size_of_val(&self) -> usize {
395        match *self {
396            FieldType::U8 => 1,
397            FieldType::U16 => 2,
398            FieldType::U32 => 4,
399            _ => 0,
400        }
401    }
402
403    fn for_val(value: u32) -> Self {
404        if u8::try_from(value).is_ok() {
405            FieldType::U8
406        } else if u16::try_from(value).is_ok() {
407            FieldType::U16
408        } else {
409            FieldType::U32
410        }
411    }
412}
413
414impl From<u8> for FieldType {
415    fn from(byte: u8) -> Self {
416        match byte {
417            0x00 => Self::U8,
418            0x01 => Self::U16,
419            0x02 => Self::U32,
420            _ => Self(byte),
421        }
422    }
423}
424
425impl From<FieldType> for u8 {
426    fn from(field_type: FieldType) -> Self {
427        field_type.0
428    }
429}
430
431/// 2.2.3.2 DVC Data PDU (DYNVC_DATA)
432///
433/// [2.2.3.2]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedyc/15b59886-db44-47f1-8da3-47c8fcd82803
434#[derive(Debug, PartialEq)]
435pub struct DataPdu {
436    header: Header,
437    pub channel_id: DynamicChannelId,
438    pub data: Vec<u8>,
439}
440
441impl DataPdu {
442    pub fn new(channel_id: DynamicChannelId, data: Vec<u8>) -> Self {
443        Self {
444            header: Header::new(channel_id, 0, Cmd::Data),
445            channel_id,
446            data,
447        }
448    }
449
450    fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
451        ensure_size!(in: src, size: header.cb_id.size_of_val());
452        let channel_id = header.cb_id.decode_val(src)?;
453        let data = src.read_remaining().to_vec();
454        Ok(Self {
455            header,
456            channel_id,
457            data,
458        })
459    }
460
461    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
462        ensure_size!(in: dst, size: self.size());
463        self.header.encode(dst)?;
464        self.header.cb_id.encode_val(self.channel_id, dst)?;
465        dst.write_slice(&self.data);
466        Ok(())
467    }
468
469    fn name() -> &'static str {
470        "DYNVC_DATA"
471    }
472
473    fn size(&self) -> usize {
474        strict_sum(&[
475            Header::size(),
476            self.header.cb_id.size_of_val(), // ChannelId
477            self.data.len(),                 // Data
478        ])
479    }
480}
481
482/// 2.2.2.2 DVC Create Response PDU (DYNVC_CREATE_RSP)
483///
484/// [2.2.2.2]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedyc/8f284ea3-54f3-4c24-8168-8a001c63b581
485#[derive(Debug, PartialEq)]
486pub struct CreateResponsePdu {
487    header: Header,
488    pub channel_id: DynamicChannelId,
489    pub creation_status: CreationStatus,
490}
491
492impl CreateResponsePdu {
493    pub fn new(channel_id: DynamicChannelId, creation_status: CreationStatus) -> Self {
494        Self {
495            header: Header::new(channel_id, 0, Cmd::Create),
496            channel_id,
497            creation_status,
498        }
499    }
500
501    fn name() -> &'static str {
502        "DYNVC_CREATE_RSP"
503    }
504
505    fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
506        ensure_size!(in: src, size: Self::headerless_size(&header));
507        let channel_id = header.cb_id.decode_val(src)?;
508        let creation_status = CreationStatus(src.read_u32());
509        Ok(Self {
510            header,
511            channel_id,
512            creation_status,
513        })
514    }
515
516    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
517        ensure_size!(in: dst, size: self.size());
518        self.header.encode(dst)?;
519        self.header.cb_id.encode_val(self.channel_id, dst)?;
520        self.creation_status.encode(dst)?;
521        Ok(())
522    }
523
524    fn headerless_size(header: &Header) -> usize {
525        strict_sum(&[
526            header.cb_id.size_of_val(), // ChannelId
527            CreationStatus::size(),     // CreationStatus
528        ])
529    }
530
531    fn size(&self) -> usize {
532        strict_sum(&[Header::size(), Self::headerless_size(&self.header)])
533    }
534}
535
536#[derive(Debug, Copy, Clone, PartialEq)]
537pub struct CreationStatus(u32);
538
539impl CreationStatus {
540    pub const OK: Self = Self(0x00000000);
541    pub const NOT_FOUND: Self = Self(0xC0000225);
542    pub const NO_LISTENER: Self = Self(0xC0000001);
543
544    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
545        ensure_size!(in: dst, size: Self::size());
546        dst.write_u32(self.0);
547        Ok(())
548    }
549
550    fn size() -> usize {
551        4
552    }
553}
554
555impl From<CreationStatus> for u32 {
556    fn from(val: CreationStatus) -> Self {
557        val.0
558    }
559}
560
561/// 2.2.4 Closing a DVC (DYNVC_CLOSE)
562///
563/// [2.2.4]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedyc/c02dfd21-ccbc-4254-985b-3ef6dd115dec
564#[derive(Debug, PartialEq)]
565pub struct ClosePdu {
566    header: Header,
567    pub channel_id: DynamicChannelId,
568}
569
570impl ClosePdu {
571    pub fn new(channel_id: DynamicChannelId) -> Self {
572        Self {
573            header: Header::new(channel_id, 0, Cmd::Close),
574            channel_id,
575        }
576    }
577
578    #[must_use]
579    pub fn with_cb_id_type(self, cb_id: FieldType) -> Self {
580        Self {
581            header: self.header.with_cb_id(cb_id),
582            ..self
583        }
584    }
585
586    fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
587        ensure_size!(in: src, size: Self::headerless_size(&header));
588        let channel_id = header.cb_id.decode_val(src)?;
589        Ok(Self { header, channel_id })
590    }
591
592    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
593        ensure_size!(in: dst, size: self.size());
594        self.header.encode(dst)?;
595        self.header.cb_id.encode_val(self.channel_id, dst)?;
596        Ok(())
597    }
598
599    fn name() -> &'static str {
600        "DYNVC_CLOSE"
601    }
602
603    fn headerless_size(header: &Header) -> usize {
604        header.cb_id.size_of_val()
605    }
606
607    fn size(&self) -> usize {
608        strict_sum(&[Header::size(), Self::headerless_size(&self.header)])
609    }
610}
611
612/// 2.2.1.2 DVC Capabilities Response PDU (DYNVC_CAPS_RSP)
613///
614/// [2.2.1.2]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedyc/d45cb2a6-e7bd-453e-8603-9c57600e24ce
615#[derive(Debug, PartialEq)]
616pub struct CapabilitiesResponsePdu {
617    header: Header,
618    version: CapsVersion,
619}
620
621impl CapabilitiesResponsePdu {
622    const HEADERLESS_FIXED_PART_SIZE: usize = 1 /* Pad */ + CapsVersion::FIXED_PART_SIZE /* Version */;
623    const FIXED_PART_SIZE: usize = Header::FIXED_PART_SIZE + Self::HEADERLESS_FIXED_PART_SIZE;
624
625    pub fn new(version: CapsVersion) -> Self {
626        Self {
627            header: Header::new(0, 0, Cmd::Capability),
628            version,
629        }
630    }
631
632    fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
633        ensure_size!(in: src, size: Self::HEADERLESS_FIXED_PART_SIZE);
634        let _pad = src.read_u8();
635        let version = CapsVersion::try_from(src.read_u16())?;
636        Ok(Self { header, version })
637    }
638
639    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
640        ensure_size!(in: dst, size: Self::size());
641        self.header.encode(dst)?;
642        dst.write_u8(0x00); // Pad, MUST be 0x00
643        self.version.encode(dst)?;
644        Ok(())
645    }
646
647    fn name() -> &'static str {
648        "DYNVC_CAPS_RSP"
649    }
650
651    fn size() -> usize {
652        Self::FIXED_PART_SIZE
653    }
654}
655
656#[repr(u16)]
657#[derive(Debug, Copy, Clone, PartialEq)]
658pub enum CapsVersion {
659    V1 = 0x0001,
660    V2 = 0x0002,
661    V3 = 0x0003,
662}
663
664impl CapsVersion {
665    const FIXED_PART_SIZE: usize = 2;
666
667    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
668        ensure_size!(in: dst, size: Self::size());
669        dst.write_u16(*self as u16);
670        Ok(())
671    }
672
673    fn size() -> usize {
674        Self::FIXED_PART_SIZE
675    }
676}
677
678impl TryFrom<u16> for CapsVersion {
679    type Error = DecodeError;
680
681    fn try_from(value: u16) -> Result<Self, Self::Error> {
682        match value {
683            0x0001 => Ok(Self::V1),
684            0x0002 => Ok(Self::V2),
685            0x0003 => Ok(Self::V3),
686            _ => Err(invalid_field_err!("CapsVersion", "invalid version")),
687        }
688    }
689}
690
691impl From<CapsVersion> for u16 {
692    fn from(version: CapsVersion) -> Self {
693        version as u16
694    }
695}
696
697/// 2.2.1.1 DVC Capabilities Request PDU
698///
699/// [2.2.1.1]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedyc/c07b15ae-304e-46b8-befe-39c6d95c25e0
700#[derive(Debug, PartialEq)]
701pub enum CapabilitiesRequestPdu {
702    V1 {
703        header: Header,
704    },
705    V2 {
706        header: Header,
707        charges: [u16; CapabilitiesRequestPdu::PRIORITY_CHARGE_COUNT],
708    },
709    V3 {
710        header: Header,
711        charges: [u16; CapabilitiesRequestPdu::PRIORITY_CHARGE_COUNT],
712    },
713}
714
715impl CapabilitiesRequestPdu {
716    const HEADERLESS_FIXED_PART_SIZE: usize = 1 /* Pad */ + 2 /* Version */;
717    const FIXED_PART_SIZE: usize = Header::FIXED_PART_SIZE + Self::HEADERLESS_FIXED_PART_SIZE;
718    const PRIORITY_CHARGE_SIZE: usize = 2; // 2 bytes for each priority charge
719    const PRIORITY_CHARGE_COUNT: usize = 4; // 4 priority charges
720    const PRIORITY_CHARGES_SIZE: usize = Self::PRIORITY_CHARGE_COUNT * Self::PRIORITY_CHARGE_SIZE;
721
722    pub fn new(version: CapsVersion, charges: Option<[u16; Self::PRIORITY_CHARGE_COUNT]>) -> Self {
723        let header = Header::new(0, 0, Cmd::Capability);
724        let charges = charges.unwrap_or([0; Self::PRIORITY_CHARGE_COUNT]);
725
726        match version {
727            CapsVersion::V1 => Self::V1 { header },
728            CapsVersion::V2 => Self::V2 { header, charges },
729            CapsVersion::V3 => Self::V3 { header, charges },
730        }
731    }
732
733    fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
734        ensure_size!(in: src, size: Self::HEADERLESS_FIXED_PART_SIZE);
735        let _pad = src.read_u8();
736        let version = CapsVersion::try_from(src.read_u16())?;
737        match version {
738            CapsVersion::V1 => Ok(Self::V1 { header }),
739            _ => {
740                ensure_size!(in: src, size: Self::PRIORITY_CHARGES_SIZE);
741                let mut charges = [0u16; Self::PRIORITY_CHARGE_COUNT];
742                for charge in charges.iter_mut() {
743                    *charge = src.read_u16();
744                }
745
746                match version {
747                    CapsVersion::V2 => Ok(Self::V2 { header, charges }),
748                    CapsVersion::V3 => Ok(Self::V3 { header, charges }),
749                    _ => unreachable!(),
750                }
751            }
752        }
753    }
754
755    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
756        ensure_size!(in: dst, size: self.size());
757        match self {
758            CapabilitiesRequestPdu::V1 { header }
759            | CapabilitiesRequestPdu::V2 { header, .. }
760            | CapabilitiesRequestPdu::V3 { header, .. } => header.encode(dst)?,
761        };
762        dst.write_u8(0x00); // Pad, MUST be 0x00
763        match self {
764            CapabilitiesRequestPdu::V1 { .. } => dst.write_u16(CapsVersion::V1.into()),
765            CapabilitiesRequestPdu::V2 { .. } => dst.write_u16(CapsVersion::V2.into()),
766            CapabilitiesRequestPdu::V3 { .. } => dst.write_u16(CapsVersion::V3.into()),
767        }
768        match self {
769            CapabilitiesRequestPdu::V1 { .. } => {}
770            CapabilitiesRequestPdu::V2 { charges, .. } | CapabilitiesRequestPdu::V3 { charges, .. } => {
771                for charge in charges.iter() {
772                    dst.write_u16(*charge);
773                }
774            }
775        }
776        Ok(())
777    }
778
779    fn size(&self) -> usize {
780        match self {
781            Self::V1 { .. } => Self::FIXED_PART_SIZE,
782            _ => Self::FIXED_PART_SIZE + Self::PRIORITY_CHARGES_SIZE,
783        }
784    }
785
786    fn name(&self) -> &'static str {
787        match self {
788            Self::V1 { .. } => "DYNVC_CAPS_VERSION1",
789            Self::V2 { .. } => "DYNVC_CAPS_VERSION2",
790            Self::V3 { .. } => "DYNVC_CAPS_VERSION3",
791        }
792    }
793}
794
795/// 2.2.2.1 DVC Create Request PDU (DYNVC_CREATE_REQ)
796///
797/// [2.2.2.1]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedyc/4448ba4d-9a72-429f-8b65-6f4ec44f2985
798#[derive(Debug, PartialEq)]
799pub struct CreateRequestPdu {
800    header: Header,
801    pub channel_id: DynamicChannelId,
802    pub channel_name: String,
803}
804
805impl CreateRequestPdu {
806    pub fn new(channel_id: DynamicChannelId, channel_name: String) -> Self {
807        Self {
808            header: Header::new(channel_id, 0, Cmd::Create),
809            channel_id,
810            channel_name,
811        }
812    }
813
814    fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
815        ensure_size!(in: src, size: Self::headerless_fixed_part_size(&header));
816        let channel_id = header.cb_id.decode_val(src)?;
817        let channel_name = read_string_from_cursor(src, CharacterSet::Ansi, true)?;
818        Ok(Self {
819            header,
820            channel_id,
821            channel_name,
822        })
823    }
824
825    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
826        ensure_size!(in: dst, size: self.size());
827        self.header.encode(dst)?;
828        self.header.cb_id.encode_val(self.channel_id, dst)?;
829        write_string_to_cursor(dst, &self.channel_name, CharacterSet::Ansi, true)?;
830        Ok(())
831    }
832
833    fn name() -> &'static str {
834        "DYNVC_CREATE_REQ"
835    }
836
837    fn headerless_fixed_part_size(header: &Header) -> usize {
838        header.cb_id.size_of_val() // ChannelId
839    }
840
841    fn size(&self) -> usize {
842        strict_sum(&[
843            Header::size(),
844            Self::headerless_fixed_part_size(&self.header), // ChannelId
845            encoded_str_len(&self.channel_name, CharacterSet::Ansi, true), // ChannelName + Null terminator
846        ])
847    }
848}