1use crate::codes;
2
3pub const MAX_DATA_SIZE: usize = 256;
4pub const NONDATA_SIZE: usize = 6;
5pub const MAX_SIZE: usize = MAX_DATA_SIZE + NONDATA_SIZE;
6
7#[derive(Debug, PartialEq, Eq, Clone, Copy)]
9pub enum Subnegotiation {
10 SetSignature {
11 data: [u8; MAX_DATA_SIZE],
12 size: u8,
13 },
14 SetBaudRate(u32),
15 SetDataSize(u8),
16 SetParity(u8),
17 SetStopSize(u8),
18 SetControl(u8),
19 NotifyLineState(u8),
20 NotifyModemState(u8),
21 FlowControlSuspend,
22 FlowControlResume,
23 SetLinestateMask(u8),
24 SetModemStateMask(u8),
25 PurgeData(u8),
26 Unsupported {
27 base_option_code: u8,
28 option_code: u8,
29 data: [u8; MAX_DATA_SIZE],
30 data_cnt: u8,
31 },
32}
33
34#[derive(Clone, Copy)]
37enum OptionKind {
38 ClientToServer,
39 ServerToClient,
40}
41
42impl Subnegotiation {
43 pub fn serialize_client(&self, buf: &mut [u8]) -> usize {
44 self.serialize(buf, OptionKind::ClientToServer)
45 }
46
47 pub fn serialize_server(&self, buf: &mut [u8]) -> usize {
48 self.serialize(buf, OptionKind::ServerToClient)
49 }
50
51 fn serialize(&self, buf: &mut [u8], option_kind: OptionKind) -> usize {
52 let start = |option_code: u8| -> [u8; 4] {
53 [
54 codes::IAC,
55 codes::SB,
56 codes::COM_PORT_OPTION,
57 match option_kind {
58 OptionKind::ClientToServer => option_code,
59 OptionKind::ServerToClient => option_code + 100,
60 },
61 ]
62 };
63
64 let end = [codes::IAC, codes::SE];
65
66 let mut subnegotiate = |option_code: u8, data: &[u8]| -> usize {
67 buf[..4].copy_from_slice(&start(option_code));
68 buf[4..4 + data.len()].copy_from_slice(data);
69 buf[4 + data.len()..NONDATA_SIZE + data.len()].copy_from_slice(&end);
70 NONDATA_SIZE + data.len()
71 };
72
73 match *self {
74 Self::SetSignature { data, size } => {
75 buf[..4].copy_from_slice(&start(0));
76 let data_slice = &data[..size as usize];
77 let mut i = 4;
78 for byte in data_slice {
79 buf[i] = *byte;
80 i += 1;
81 if *byte == codes::IAC {
83 buf[i] = *byte;
84 i += 1;
85 }
86 }
87 buf[i..i + 2].copy_from_slice(&end);
88 i + 2
89 }
90
91 Self::SetBaudRate(baud) => subnegotiate(1, &u32::to_be_bytes(baud)),
92 Self::SetDataSize(data_size) => subnegotiate(2, &[data_size]),
93 Self::SetParity(parity) => subnegotiate(3, &[parity]),
94 Self::SetStopSize(stopsize) => subnegotiate(4, &[stopsize]),
95 Self::SetControl(control) => subnegotiate(5, &[control]),
96 Self::NotifyLineState(linestate) => subnegotiate(6, &[linestate]),
97 Self::NotifyModemState(modemstate) => subnegotiate(7, &[modemstate]),
98 Self::FlowControlSuspend => subnegotiate(8, &[]),
99 Self::FlowControlResume => subnegotiate(9, &[]),
100 Self::SetLinestateMask(linestate_mask) => subnegotiate(10, &[linestate_mask]),
101 Self::SetModemStateMask(modemstate_mask) => subnegotiate(11, &[modemstate_mask]),
102 Self::PurgeData(purge_data) => subnegotiate(12, &[purge_data]),
103 Self::Unsupported {
104 base_option_code,
105 option_code,
106 data,
107 data_cnt,
108 } => {
109 buf[..4].copy_from_slice(&[codes::IAC, codes::SB, base_option_code, option_code]);
110 buf[4..4 + data_cnt as usize].copy_from_slice(&data[..data_cnt as usize]);
111 buf[4 + data_cnt as usize..NONDATA_SIZE + data_cnt as usize].copy_from_slice(&end);
112 NONDATA_SIZE + data_cnt as usize
113 }
114 }
115 }
116
117 pub fn deserialize(buf: &[u8]) -> Self {
118 assert!(
119 buf[0] == codes::IAC
120 && buf[1] == codes::SB
121 && buf[buf.len() - 2] == codes::IAC
122 && buf[buf.len() - 1] == codes::SE
123 );
124
125 let base_option_code = buf[2];
126 let option_code = buf[3];
127 let data_len = buf.len() - NONDATA_SIZE;
128 let data = &buf[4..4 + data_len];
129
130 match base_option_code {
131 codes::COM_PORT_OPTION => match option_code {
132 0 | 100 => {
133 let mut data_no_escapes = [0; MAX_DATA_SIZE];
134 let mut i = 0;
135 let mut iac_occured = false;
136 for &byte in data {
137 if byte == codes::IAC {
138 if iac_occured {
139 iac_occured = false;
140 continue;
141 } else {
142 iac_occured = true;
143 }
144 }
145 data_no_escapes[i] = byte;
146 i += 1;
147 }
148 Self::SetSignature {
149 data: data_no_escapes,
150 size: i as u8,
151 }
152 }
153 1 | 101 => {
154 let baud_rate = u32::from_be_bytes([data[0], data[1], data[2], data[3]]);
155 Self::SetBaudRate(baud_rate)
156 }
157 2 | 102 => Self::SetDataSize(data[0]),
158 3 | 103 => Self::SetParity(data[0]),
159 4 | 104 => Self::SetStopSize(data[0]),
160 5 | 105 => Self::SetControl(data[0]),
161 6 | 106 => Self::NotifyLineState(data[0]),
162 7 | 107 => Self::NotifyModemState(data[0]),
163 8 | 108 => Self::FlowControlSuspend,
164 9 | 109 => Self::FlowControlResume,
165 10 | 110 => Self::SetLinestateMask(data[0]),
166 11 | 111 => Self::SetModemStateMask(data[0]),
167 12 | 112 => Self::PurgeData(data[0]),
168 _ => panic!("Option code is not a Com Port option code"),
169 },
170 _ => {
171 let mut data_arr = [0; MAX_DATA_SIZE];
172 data_arr.copy_from_slice(data);
173 Self::Unsupported {
174 base_option_code: base_option_code,
175 option_code: option_code,
176 data: data_arr,
177 data_cnt: data_len as u8,
178 }
179 }
180 }
181 }
182}