pn_dcp/options/
mod.rs

1use crate::comm::BytesWrap;
2use crate::packet::ident_resp::PacketIdentResp;
3use anyhow::{bail, Result};
4use std::fmt::{Debug, Formatter};
5use std::net::Ipv4Addr;
6
7// static const value_string pn_dcp_block_info[] = {
8// { 0x0000, "RESERVED" },
9// /*0x0001 - 0xffff reserved */
10// { 0, NULL }
11// };
12#[derive(Debug, Eq, PartialEq, Clone)]
13pub enum BlockInfo {
14    Reserved,
15    UnSupport([u8; 2]),
16}
17impl BlockInfo {
18    pub fn to_u8_array(&self) -> [u8; 2] {
19        match self {
20            Self::Reserved => [0x00, 0x00],
21            Self::UnSupport(a) => a.clone(),
22        }
23    }
24}
25
26impl TryFrom<BytesWrap> for BlockInfo {
27    type Error = anyhow::Error;
28
29    fn try_from(value: BytesWrap) -> std::result::Result<Self, Self::Error> {
30        let val = value.slice(0..=1)?;
31        let data = [val.as_ref()[0], val.as_ref()[1]];
32        Ok(match data {
33            RESERVED => Self::Reserved,
34            data => Self::UnSupport(data),
35        })
36    }
37}
38
39const RESERVED: [u8; 2] = [0x00, 0x00];
40const USE_TEMPORARY: [u8; 2] = [0x00, 0x00];
41const SAVE_PERMANENT: [u8; 2] = [0x00, 0x01];
42#[derive(Eq, PartialEq, Clone)]
43pub enum BlockQualifier {
44    UseTemporary,
45    SavePermanent,
46    UnSupport([u8; 2]),
47}
48impl BlockQualifier {
49    pub fn to_u8_array(&self) -> [u8; 2] {
50        match self {
51            Self::UnSupport(a) => a.clone(),
52            Self::UseTemporary => USE_TEMPORARY,
53            Self::SavePermanent => SAVE_PERMANENT,
54        }
55    }
56}
57impl Debug for BlockQualifier {
58    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
59        match self {
60            Self::UseTemporary => {
61                write!(f, "Use the value temporary")
62            }
63            Self::SavePermanent => {
64                write!(f, "Save the value permanent")
65            }
66            Self::UnSupport(a) => {
67                write!(f, "UnSupport value {:?}", a)
68            }
69        }
70    }
71}
72impl TryFrom<BytesWrap> for BlockQualifier {
73    type Error = anyhow::Error;
74
75    fn try_from(value: BytesWrap) -> std::result::Result<Self, Self::Error> {
76        let val = value.slice(0..=1)?;
77        let a = [val.as_ref()[0], val.as_ref()[1]];
78        Ok(match a {
79            USE_TEMPORARY => Self::UseTemporary,
80            SAVE_PERMANENT => Self::SavePermanent,
81            b => Self::UnSupport(b),
82        })
83    }
84}
85#[derive(Debug, Eq, PartialEq, Clone)]
86pub struct InnerIpAddr(pub Ipv4Addr, pub Ipv4Addr, pub Ipv4Addr);
87impl InnerIpAddr {
88    pub fn new(data: BytesWrap) -> Result<Self> {
89        let val = data.slice(0..=11)?;
90        let val = val.as_ref();
91        Ok(Self(
92            Ipv4Addr::new(val[0], val[1], val[2], val[3]),
93            Ipv4Addr::new(val[4], val[5], val[6], val[7]),
94            Ipv4Addr::new(val[8], val[9], val[10], val[11]),
95        ))
96    }
97    pub fn new_by_ipv4(ip: Ipv4Addr, subnetmask: Ipv4Addr, gateway: Ipv4Addr) -> Self {
98        Self(ip, subnetmask, gateway)
99    }
100    pub fn append_value_to_data(&self, data: &mut Vec<u8>) {
101        data.extend_from_slice(self.0.octets().as_slice());
102        data.extend_from_slice(self.1.octets().as_slice());
103        data.extend_from_slice(self.2.octets().as_slice());
104    }
105    pub fn payload_size(&self) -> usize {
106        12
107    }
108    pub fn to_option(self) -> OptionAndSubValue {
109        OptionAndSubValue::IpAddr(self)
110    }
111
112    pub fn append_to_ident_resp(self, packet: &mut PacketIdentResp, info: IpBlockInfo) {
113        packet.append_block_ip(self, info)
114    }
115}
116
117#[derive(Debug, Eq, PartialEq, Clone)]
118pub struct Response(pub OptionAndSub, pub BlockError);
119impl Response {
120    pub fn len(&self) -> usize {
121        5
122    }
123    pub fn payload(&self) -> u16 {
124        3
125    }
126    pub fn append_value_to_data(&self, data: &mut Vec<u8>) {
127        data.extend_from_slice(self.0.to_u8_array().as_slice());
128        data.push(self.1 as u8);
129    }
130    pub fn to_option(self) -> OptionAndSubValue {
131        OptionAndSubValue::Response(self)
132    }
133}
134
135impl TryFrom<BytesWrap> for Response {
136    type Error = anyhow::Error;
137    fn try_from(data: BytesWrap) -> Result<Self, Self::Error> {
138        let val = data.slice(0..=2)?;
139        let ref_u8 = val.as_ref();
140        Ok(Self(
141            OptionAndSub::try_from(val.clone())?,
142            BlockError::try_from(ref_u8[2])?,
143        ))
144    }
145}
146
147#[derive(Default)]
148pub struct DeviceOptionsBuilder(Vec<OptionAndSub>);
149
150impl DeviceOptionsBuilder {
151    pub fn append_option(mut self, option: OptionAndSub) -> Self {
152        self.0.push(option);
153        self
154    }
155    pub fn build(self) -> OptionAndSubValue {
156        OptionAndSubValue::DeviceOptions(self.0)
157    }
158}
159
160#[derive(Debug, Eq, PartialEq, Clone)]
161pub enum OptionAndSubValue {
162    // MarAddr([u8; 6]),
163    IpAddr(InnerIpAddr),
164    // FullIpSuite(Ipv4Addr, Ipv4Addr, Ipv4Addr, Ipv4Addr),
165    ManufacturerSpecific(BytesWrap),
166    NameOfStation(BytesWrap),
167    DeviceId([u8; 2], [u8; 2]),
168    DeviceRole(u8, u8), //DeviceRoleDetails + reserved
169    DeviceOptions(Vec<OptionAndSub>),
170    // AliasName, //Filter only?
171    // StartTransaction,
172    // EndTransaction,
173    // Signal,
174    Response(Response), // not support yet
175                        // ResetFactory,
176                        // DevicecInitiative,
177                        All,
178                        // DHCP(u8),
179                        // LLDP(u8),
180                        Other(OptionAndSub, BytesWrap),
181}
182
183impl OptionAndSubValue {
184    pub fn append_option_to_data(&self, data: &mut Vec<u8>) {
185        match self {
186            Self::IpAddr(_) => {
187                data.extend_from_slice(OptionAndSub::IpAddr.to_u8_array().as_slice())
188            }
189            // Self::FullIpSuite(_, _, _, _) => 16,
190            Self::ManufacturerSpecific(_) => {
191                data.extend_from_slice(OptionAndSub::ManufacturerSpecific.to_u8_array().as_slice())
192            }
193            Self::NameOfStation(_) => {
194                data.extend_from_slice(OptionAndSub::NameOfStation.to_u8_array().as_slice())
195            }
196            Self::DeviceId(_, _) => {
197                data.extend_from_slice(OptionAndSub::DeviceId.to_u8_array().as_slice())
198            }
199            Self::DeviceRole(_, _) => {
200                data.extend_from_slice(OptionAndSub::DeviceRole.to_u8_array().as_slice())
201            }
202            Self::DeviceOptions(_) => {
203                data.extend_from_slice(OptionAndSub::DeviceOptions.to_u8_array().as_slice())
204            }
205            Self::Response(_) => {
206                data.extend_from_slice(OptionAndSub::Response.to_u8_array().as_slice())
207            }
208            Self::All => {
209                data.extend_from_slice(OptionAndSub::All.to_u8_array().as_slice())
210            }
211            Self::Other(a, _) => {
212                data.extend_from_slice(a.to_u8_array().as_slice())
213            }
214        }
215    }
216    pub fn append_value_to_data(&self, data: &mut Vec<u8>) {
217        match self {
218            Self::IpAddr(a) => {
219                data.extend_from_slice(a.0.octets().as_slice());
220                data.extend_from_slice(a.1.octets().as_slice());
221                data.extend_from_slice(a.2.octets().as_slice());
222            }
223            // Self::FullIpSuite(_, _, _, _) => 16,
224            Self::ManufacturerSpecific(val) => {
225                data.extend_from_slice(val.as_ref());
226            }
227            Self::NameOfStation(val) => {
228                data.extend_from_slice(val.as_ref());
229            }
230            Self::DeviceId(a, b) => {
231                data.extend_from_slice(a.as_ref());
232                data.extend_from_slice(b.as_ref());
233            }
234            Self::DeviceRole(a, b) => {
235                data.push(*a);
236                data.push(*b);
237            }
238            Self::DeviceOptions(val) => {
239                for option in val {
240                    data.extend_from_slice(option.to_u8_array().as_slice());
241                }
242            }
243            Self::Response(a) => {
244                a.append_value_to_data(data);
245            }
246            Self::All => {
247            }
248            Self::Other(_, a) => {
249                data.extend_from_slice(a.as_ref())
250            }
251        }
252    }
253    // data的长度校验,应该等于求出来的值
254    pub fn init_by_ty(ty: OptionAndSub, data: BytesWrap) -> Result<Self> {
255        Ok(match ty {
256            OptionAndSub::IpAddr => {
257                let val = data.slice(0..=11)?;
258                let val = val.as_ref();
259                Self::IpAddr(InnerIpAddr(
260                    Ipv4Addr::new(val[0], val[1], val[2], val[3]),
261                    Ipv4Addr::new(val[4], val[5], val[6], val[7]),
262                    Ipv4Addr::new(val[8], val[9], val[10], val[11]),
263                ))
264            }
265            OptionAndSub::ManufacturerSpecific => Self::ManufacturerSpecific(data),
266            OptionAndSub::NameOfStation => Self::NameOfStation(data),
267            OptionAndSub::DeviceId => {
268                let val = data.slice(0..=3)?;
269                let val = val.as_ref();
270                Self::DeviceId([val[0], val[1]], [val[2], val[3]])
271            }
272            OptionAndSub::DeviceRole => {
273                let val = data.slice(0..=1)?;
274                let val = val.as_ref();
275                Self::DeviceRole(val[0], val[1])
276            }
277            OptionAndSub::DeviceOptions => {
278                let mut index = 0;
279                let mut options = Vec::new();
280                while let Ok(val) = data.slice(index..) {
281                    if val.len() == 0 {
282                        break;
283                    }
284                    options.push(OptionAndSub::try_from(val)?);
285                    index += 2;
286                }
287                Self::DeviceOptions(options)
288            }
289            OptionAndSub::Response => {
290                let val = data.slice(0..=2)?;
291                Self::Response(Response::try_from(val)?)
292            }
293            OptionAndSub::All => {
294                Self::All
295            }
296            option => {
297                Self::Other(option, data)
298            }
299        })
300    }
301    pub fn payload_size(&self) -> usize {
302        match self {
303            Self::IpAddr(_) => 12,
304            // Self::FullIpSuite(_, _, _, _) => 16,
305            Self::ManufacturerSpecific(val) => val.len(),
306            Self::NameOfStation(val) => val.len(),
307            Self::DeviceId(_, _) => 4,
308            Self::DeviceRole(_, _) => 2,
309            Self::DeviceOptions(val) => val.len() * 2,
310            Self::Response(_) => 3,
311            Self::All => 0,
312            Self::Other(_, a) => a.len(),
313        }
314    }
315
316    pub fn append_to_ident_resp_default(self, packet: &mut PacketIdentResp) {
317        packet.append_block_common_default(self);
318    }
319    pub fn append_to_ident_resp(self, packet: &mut PacketIdentResp, info: BlockInfo) {
320        packet.append_block_common(self, info);
321    }
322}
323
324#[derive(Debug, Clone, Copy, Eq, PartialEq)]
325pub enum OptionAndSub {
326    MarAddr,
327    IpAddr,
328    FullIpSuite,
329    ManufacturerSpecific,
330    NameOfStation,
331    DeviceId,
332    DeviceRole,
333    DeviceOptions,
334    AliasName,
335    StartTransaction,
336    EndTransaction,
337    Signal,
338    Response,
339    ResetFactory,
340    DevicecInitiative,
341    All,
342    DHCP(u8),
343    LLDP(u8),
344    Other(u8, u8),
345}
346
347impl TryFrom<BytesWrap> for OptionAndSub {
348    type Error = anyhow::Error;
349
350    fn try_from(value: BytesWrap) -> std::result::Result<Self, Self::Error> {
351        if let Some(a) = value.as_ref().get(0..=1) {
352            OptionAndSub::new(a[0], a[1])
353        } else {
354            bail!("todo: {:?}", value);
355        }
356    }
357}
358
359impl OptionAndSub {
360    pub fn new(b: u8, c: u8) -> Result<Self> {
361        let a = (b, c);
362        Ok(match a {
363            (1, 1) => Self::MarAddr,
364            (1, 2) => Self::IpAddr,
365            (1, 3) => Self::FullIpSuite,
366            (2, 1) => Self::ManufacturerSpecific,
367            (2, 2) => Self::NameOfStation,
368            (2, 3) => Self::DeviceId,
369            (2, 4) => Self::DeviceRole,
370            (2, 5) => Self::DeviceOptions,
371            (2, 6) => Self::AliasName,
372            (5, 1) => Self::StartTransaction,
373            (5, 2) => Self::EndTransaction,
374            (5, 3) => Self::Signal,
375            (5, 4) => Self::Response,
376            (5, 6) => Self::ResetFactory,
377            (6, 1) => Self::DevicecInitiative,
378            (255, 255) => Self::All,
379            (3, a) => Self::DHCP(a),
380            (4, a) => Self::LLDP(a),
381            (a, b) => Self::Other(a, b),
382        })
383    }
384    pub fn to_u8s(&self) -> (u8, u8) {
385        match *self {
386            Self::MarAddr => (1, 1),
387            Self::IpAddr => (1, 2),
388            Self::FullIpSuite => (1, 3),
389            Self::ManufacturerSpecific => (2, 1),
390            Self::NameOfStation => (2, 2),
391            Self::DeviceId => (2, 3),
392            Self::DeviceRole => (2, 4),
393            Self::DeviceOptions => (2, 5),
394            Self::AliasName => (2, 6),
395            Self::StartTransaction => (5, 1),
396            Self::EndTransaction => (5, 2),
397            Self::Signal => (5, 3),
398            Self::Response => (5, 4),
399            Self::ResetFactory => (5, 6),
400            Self::DevicecInitiative => (6, 1),
401            Self::All => (255, 255),
402            Self::DHCP(a) => (3, a),
403            Self::LLDP(a) => (4, a),
404            Self::Other(a, b) => (a, b),
405        }
406    }
407    #[inline]
408    pub fn to_u8_array(&self) -> [u8; 2] {
409        match *self {
410            Self::MarAddr => [1, 1],
411            Self::IpAddr => [1, 2],
412            Self::FullIpSuite => [1, 3],
413            Self::ManufacturerSpecific => [2, 1],
414            Self::NameOfStation => [2, 2],
415            Self::DeviceId => [2, 3],
416            Self::DeviceRole => [2, 4],
417            Self::DeviceOptions => [2, 5],
418            Self::AliasName => [2, 6],
419            Self::StartTransaction => [5, 1],
420            Self::EndTransaction => [5, 2],
421            Self::Signal => [5, 3],
422            Self::Response => [5, 4],
423            Self::ResetFactory => [5, 6],
424            Self::DevicecInitiative => [6, 1],
425            Self::All => [255, 255],
426            Self::DHCP(a) => [3, a],
427            Self::LLDP(a) => [4, a],
428            Self::Other(a, b) => [a, b],
429        }
430    }
431}
432#[derive(Debug, Copy, Clone, Eq, PartialEq)]
433#[repr(u8)]
434pub enum BlockError {
435    Ok = 0x00,
436    OptionUnsupp = 0x01,
437    SuboptionUnsuppOrNoDataSetAvail = 0x02,
438    SuboptionNotSet = 0x03,
439    ResourceError = 0x04,
440    SETNotPossibleByLocalReasons = 0x05,
441    InOoperationSETNotPossible = 0x06,
442}
443
444impl TryFrom<u8> for BlockError {
445    type Error = anyhow::Error;
446
447    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
448        Ok(match value {
449            0x00 => Self::Ok,
450            0x01 => Self::OptionUnsupp,
451            0x02 => Self::SuboptionUnsuppOrNoDataSetAvail,
452            0x03 => Self::SuboptionNotSet,
453            0x04 => Self::ResourceError,
454            0x05 => Self::SETNotPossibleByLocalReasons,
455            0x06 => Self::InOoperationSETNotPossible,
456            a => bail!("unsupport block error: {}", a),
457        })
458    }
459}
460
461#[derive(Debug, Eq, PartialEq, Copy, Clone)]
462pub enum IpBlockInfo {
463    IpNotSet,
464    IpSet,
465    IpSetByDhcp,
466    IpNotSetConflict,
467    IpSetConflict,
468    IpSetByDhcpConflict,
469    UnSupport([u8; 2]),
470}
471
472impl Default for IpBlockInfo {
473    fn default() -> Self {
474        Self::IpSet
475    }
476}
477
478impl IpBlockInfo {
479    pub fn to_u8_array(&self) -> [u8; 2] {
480        match self {
481            Self::IpNotSet => [0x00, 0x00],
482            Self::IpSet => [0x00, 0x01],
483            Self::IpSetByDhcp => [0x00, 0x02],
484            Self::IpNotSetConflict => [0x00, 0x80],
485            Self::IpSetConflict => [0x00, 0x81],
486            Self::IpSetByDhcpConflict => [0x00, 0x82],
487            Self::UnSupport(data) => data.clone(),
488        }
489    }
490}
491
492impl TryFrom<BytesWrap> for IpBlockInfo {
493    type Error = anyhow::Error;
494    fn try_from(value: BytesWrap) -> Result<Self, Self::Error> {
495        let val = value.slice(0..=1)?;
496        let data = [val.as_ref()[0], val.as_ref()[1]];
497        Ok(match data {
498            [0x00, 0x00] => Self::IpNotSet,
499            [0x00, 0x01] => Self::IpSet,
500            [0x00, 0x02] => Self::IpSetByDhcp,
501            [0x00, 0x80] => Self::IpNotSetConflict,
502            [0x00, 0x81] => Self::IpSetConflict,
503            [0x00, 0x82] => Self::IpSetByDhcpConflict,
504            data => Self::UnSupport(data),
505        })
506    }
507}