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
65pub 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)] #[br(assert(flags == 0))]
81 flags: u32,
82 lease_key: Guid,
83 lease_state: LeaseState,
84 #[bw(calc = 0)] #[br(assert(lease_duration == 0))]
86 lease_duration: u64,
87}
88
89pub 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}