smb_msg/
oplock.rs

1use crate::FileId;
2use binrw::prelude::*;
3use modular_bitfield::prelude::*;
4use smb_dtyp::Guid;
5
6#[binrw::binrw]
7#[derive(Debug, PartialEq, Eq)]
8pub struct OplockBreakMsg {
9    #[bw(calc = 24)]
10    #[br(assert(_structure_size == 24))]
11    _structure_size: u16,
12    oplock_level: u8,
13    #[bw(calc = 0)]
14    #[br(assert(_reserved == 0))]
15    _reserved: u8,
16    #[bw(calc = 0)]
17    #[br(assert(reserved2 == 0))]
18    reserved2: u32,
19    file_id: FileId,
20}
21
22#[binrw::binrw]
23#[derive(Debug, PartialEq, Eq)]
24pub struct LeaseBreakNotify {
25    #[bw(calc = 44)]
26    #[br(assert(_structure_size == 44))]
27    _structure_size: u16,
28    new_epoch: u16,
29    ack_required: u32,
30    lease_key: Guid,
31    current_lease_state: LeaseState,
32    new_lease_state: LeaseState,
33    #[bw(calc = 0)]
34    #[br(assert(break_reason == 0))]
35    break_reason: u32,
36    #[bw(calc = 0)]
37    #[br(assert(access_mask_hint == 0))]
38    access_mask_hint: u32,
39    #[bw(calc = 0)]
40    #[br(assert(share_mask_hint == 0))]
41    share_mask_hint: u32,
42}
43
44#[binrw::binrw]
45#[derive(Debug, PartialEq, Eq)]
46#[brw(repr(u8))]
47pub enum OplockLevel {
48    None = 0,
49    II = 1,
50    Exclusive = 2,
51}
52
53#[bitfield]
54#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
55#[bw(map = |&x| Self::into_bytes(x))]
56#[br(map = Self::from_bytes)]
57pub struct LeaseState {
58    pub read_caching: bool,
59    pub handle_caching: bool,
60    pub write_caching: bool,
61    #[skip]
62    __: B29,
63}
64
65// Those are all the same.
66pub type OplockBreakNotify = OplockBreakMsg;
67pub type OplockBreakAck = OplockBreakMsg;
68pub type OplockBreakResponse = OplockBreakMsg;
69
70#[binrw::binrw]
71#[derive(Debug, PartialEq, Eq)]
72pub struct LeaseBreakAckResponse {
73    #[bw(calc = 36)]
74    #[br(assert(_structure_size == 36))]
75    _structure_size: u16,
76    #[bw(calc = 0)]
77    #[br(assert(_reserved == 0))]
78    _reserved: u16,
79    #[bw(calc = 0)] // reserved
80    #[br(assert(flags == 0))]
81    flags: u32,
82    lease_key: Guid,
83    lease_state: LeaseState,
84    #[bw(calc = 0)] // reserved
85    #[br(assert(lease_duration == 0))]
86    lease_duration: u64,
87}
88
89// Those are the same.
90pub type LeaseBreakAck = LeaseBreakAckResponse;
91pub type LeaseBreakResponse = LeaseBreakAckResponse;
92
93#[cfg(test)]
94mod tests {
95    use crate::*;
96    use std::io::Cursor;
97
98    use super::*;
99    #[test]
100    pub fn test_lease_break_notify_parses() {
101        let data = [
102            0x2c, 0x0, 0x2, 0x0, 0x1, 0x0, 0x0, 0x0, 0x9e, 0x61, 0xc8, 0x70, 0x5d, 0x16, 0x5e,
103            0x31, 0xd4, 0x92, 0xa0, 0x1b, 0xc, 0xbb, 0x3a, 0xf2, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
104            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
105        ];
106
107        let parsed = LeaseBreakNotify::read_le(&mut Cursor::new(&data)).unwrap();
108        assert_eq!(
109            parsed,
110            LeaseBreakNotify {
111                new_epoch: 2,
112                ack_required: 1,
113                lease_key: "70c8619e-165d-315e-d492-a01b0cbb3af2".parse().unwrap(),
114                current_lease_state: LeaseState::new()
115                    .with_read_caching(true)
116                    .with_handle_caching(true),
117                new_lease_state: LeaseState::new()
118            }
119        )
120    }
121
122    #[test]
123    pub fn test_lease_break_ack_response_write() {
124        let req_data = encode_content(RequestContent::LeaseBreakAck(LeaseBreakAck {
125            lease_key: "70c8619e-165d-315e-d492-a01b0cbb3af2".parse().unwrap(),
126            lease_state: LeaseState::new(),
127        }));
128
129        assert_eq!(
130            req_data,
131            [
132                0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9e, 0x61, 0xc8, 0x70, 0x5d, 0x16, 0x5e,
133                0x31, 0xd4, 0x92, 0xa0, 0x1b, 0xc, 0xbb, 0x3a, 0xf2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
134                0x0, 0x0, 0x0, 0x0, 0x0, 0x0
135            ]
136        )
137    }
138
139    #[test]
140    pub fn test_lease_break_ack_response_parses() {
141        let data = [
142            0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9e, 0x61, 0xc8, 0x70, 0x5d, 0x16, 0x5e,
143            0x31, 0xd4, 0x92, 0xa0, 0x1b, 0xc, 0xbb, 0x3a, 0xf2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
144            0x0, 0x0, 0x0, 0x0, 0x0,
145        ];
146        let parsed = LeaseBreakAckResponse::read_le(&mut Cursor::new(&data)).unwrap();
147        assert_eq!(
148            parsed,
149            LeaseBreakAckResponse {
150                lease_key: "70c8619e-165d-315e-d492-a01b0cbb3af2".parse().unwrap(),
151                lease_state: LeaseState::new(),
152            }
153        )
154    }
155}