1use crate::pktparser;
22use byteorder::{BigEndian, WriteBytesExt};
23use pktparser::{Deserialise, Serialise};
24
25use std::convert::TryInto;
26use std::fmt::Formatter;
27use std::io::ErrorKind;
28
29#[derive(Debug, Eq, PartialEq)]
34pub struct LldpPacket {
35 pub tlvs: Vec<LldpTlv>,
36}
37
38impl LldpPacket {
39 fn validate_format(&self) -> Result<(), std::io::Error> {
40 if self.tlvs.len() < 4 {
41 return Err(std::io::Error::new(
42 ErrorKind::InvalidData,
43 "At least 4 mandatory TLVs are required in an LLDP PDU.",
44 ));
45 }
46
47 let first: &LldpTlv = self.tlvs.first().unwrap();
49 let second: &LldpTlv = self.tlvs.get(1).unwrap();
50 let third: &LldpTlv = self.tlvs.get(2).unwrap();
51 let last: &LldpTlv = self.tlvs.last().unwrap();
52
53 if !matches!(first, LldpTlv::ChassisID(_)) {
54 return Err(std::io::Error::new(
55 ErrorKind::InvalidData,
56 format!("Expected first TLV to be ChassisID but got {}", first),
57 ));
58 }
59 if !matches!(second, LldpTlv::PortID(_)) {
60 return Err(std::io::Error::new(
61 ErrorKind::InvalidData,
62 format!("Expected second TLV to be PortID but got {}", second),
63 ));
64 }
65 if !matches!(third, LldpTlv::TTL(_)) {
66 return Err(std::io::Error::new(
67 ErrorKind::InvalidData,
68 format!("Expected third TLV to be TTL but got {}", third),
69 ));
70 }
71 if !matches!(last, LldpTlv::EndOfLLDPPDU()) {
72 return Err(std::io::Error::new(
73 ErrorKind::InvalidData,
74 format!("Expected last TLV to be EndOfLLDPPDU but got {}", last),
75 ));
76 }
77
78 Ok(())
79 }
80}
81
82impl Serialise for LldpPacket {
83 fn to_wire(&self) -> Result<Vec<u8>, std::io::Error> {
84 self.validate_format()?;
85 let mut pdu = Vec::new();
86
87 for tlv in &self.tlvs {
88 pdu.append(&mut tlv.to_wire()?);
89 }
90
91 Ok(pdu)
92 }
93}
94
95impl Deserialise for LldpPacket {
96 fn from_wire(
97 buf: &mut pktparser::Buffer<'_>,
98 ) -> std::result::Result<Self, pktparser::ParseError> {
99 let mut tlvs = Vec::new();
100 while buf.remaining() > 0 {
101 tlvs.push(LldpTlv::from_wire(buf)?);
102 if matches!(tlvs[tlvs.len() - 1], LldpTlv::EndOfLLDPPDU()) {
103 return Ok(LldpPacket { tlvs });
104 }
105 }
106 Err(pktparser::ParseError::InvalidArgument(
107 "Malformed LLDP packet: missing End of LLDP PDU TLV".to_string(),
108 ))
109 }
110}
111
112impl std::fmt::Display for LldpPacket {
113 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
114 writeln!(f, "LLDP [")?;
115 for tlv in &self.tlvs {
116 writeln!(f, "\t{}", tlv)?;
117 }
118 write!(f, "]")
119 }
120}
121
122#[derive(Debug, Eq, PartialEq)]
123pub struct LldpTlvHeader {
124 pub ty: u8, pub length: u16, }
127
128impl Serialise for LldpTlvHeader {
129 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
130 let out: u16 = ((self.ty as u16) << 9) | (0b0000_0001_1111_1111 & self.length);
131 let mut vec = vec![];
132 WriteBytesExt::write_u16::<BigEndian>(&mut vec, out)?;
133 Ok(vec)
134 }
135}
136
137impl Deserialise for LldpTlvHeader {
138 fn from_wire(
139 buf: &mut pktparser::Buffer<'_>,
140 ) -> std::result::Result<Self, pktparser::ParseError> {
141 let input = buf
142 .get_be16()
143 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
144 let r#type = ((input & 0b1111_1110_0000_0000) >> 9) as u8;
145 let length = input & 0b0000_0001_1111_1111;
146
147 Ok(LldpTlvHeader { ty: r#type, length })
148 }
149}
150
151#[derive(Debug, Eq, PartialEq)]
152pub enum LldpTlv {
153 ChassisID(ChassisId),
155 PortID(PortId),
157 TTL(Ttl),
159 PortDescription(PortDescription),
161 SystemName(SystemName),
163 SystemDescription(SystemDescription),
165 SystemCapabilities(SystemCapabilities),
167 ManagementAddress(ManagementAddress),
169 OrganizationSpecific(OrganizationSpecific),
171
172 UnknownTLV(UnknownTlv),
174
175 EndOfLLDPPDU(),
176}
177
178impl Serialise for LldpTlv {
179 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
180 let mut tlv_hdr = LldpTlvHeader { ty: 0, length: 0 };
181 let mut payload: Vec<u8>;
182 match self {
183 Self::ChassisID(tlv) => {
184 tlv_hdr.ty = 1;
185 payload = tlv.to_wire()?;
186 }
187 Self::PortID(tlv) => {
188 tlv_hdr.ty = 2;
189 payload = tlv.to_wire()?;
190 }
191 Self::TTL(tlv) => {
192 tlv_hdr.ty = 3;
193 payload = tlv.to_wire()?;
194 }
195 Self::PortDescription(tlv) => {
196 tlv_hdr.ty = 4;
197 payload = tlv.to_wire()?;
198 }
199 Self::SystemName(tlv) => {
200 tlv_hdr.ty = 5;
201 payload = tlv.to_wire()?;
202 }
203 Self::SystemDescription(tlv) => {
204 tlv_hdr.ty = 6;
205 payload = tlv.to_wire()?;
206 }
207 Self::SystemCapabilities(tlv) => {
208 tlv_hdr.ty = 7;
209 payload = tlv.to_wire()?;
210 }
211 Self::ManagementAddress(tlv) => {
212 tlv_hdr.ty = 8;
213 payload = tlv.to_wire()?;
214 }
215 Self::OrganizationSpecific(tlv) => {
216 tlv_hdr.ty = 127;
217 payload = tlv.to_wire()?;
218 }
219 Self::UnknownTLV(tlv) => {
220 tlv_hdr.ty = tlv.ty;
221 payload = tlv.payload.clone();
222 }
223 Self::EndOfLLDPPDU() => {
224 tlv_hdr.ty = 0;
225 payload = vec![];
226 }
227 };
228 tlv_hdr.length = payload.len() as u16;
229 let mut result = tlv_hdr.to_wire()?;
230 result.append(&mut payload);
231 Ok(result)
232 }
233}
234
235impl Deserialise for LldpTlv {
236 fn from_wire(buf: &mut pktparser::Buffer<'_>) -> Result<Self, pktparser::ParseError>
237 where
238 Self: Sized,
239 {
240 let ty = ((buf
241 .get_u8()
242 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?)
243 & 0b1111_1110)
244 >> 1;
245 let len = buf
246 .get_u8()
247 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
248 let mut payload = buf
249 .get_buffer(len.into())
250 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
251
252 match ty {
253 0 => Ok(Self::EndOfLLDPPDU()),
254 1 => Ok(LldpTlv::ChassisID(ChassisId::from_wire(&mut payload)?)),
255 2 => Ok(LldpTlv::PortID(PortId::from_wire(&mut payload)?)),
256 3 => Ok(LldpTlv::TTL(Ttl::from_wire(&mut payload)?)),
257 4 => Ok(LldpTlv::PortDescription(PortDescription::from_wire(
258 &mut payload,
259 )?)),
260 5 => Ok(LldpTlv::SystemName(SystemName::from_wire(&mut payload)?)),
261 6 => Ok(LldpTlv::SystemDescription(SystemDescription::from_wire(
262 &mut payload,
263 )?)),
264 7 => Ok(LldpTlv::SystemCapabilities(SystemCapabilities::from_wire(
265 &mut payload,
266 )?)),
267 8 => Ok(LldpTlv::ManagementAddress(ManagementAddress::from_wire(
268 &mut payload,
269 )?)),
270 127 => Ok(LldpTlv::OrganizationSpecific(
271 OrganizationSpecific::from_wire(&mut payload)?,
272 )),
273 _ => {
274 let payload_vec = payload
275 .get_vec(payload.remaining())
276 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
277 Ok(LldpTlv::UnknownTLV(UnknownTlv {
278 ty,
279 payload: payload_vec,
280 }))
281 }
282 }
283 }
284}
285
286impl std::fmt::Display for LldpTlv {
287 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
288 match self {
289 Self::ChassisID(tlv) => tlv.fmt(f),
290 Self::PortID(tlv) => tlv.fmt(f),
291 Self::TTL(tlv) => tlv.fmt(f),
292 Self::PortDescription(tlv) => tlv.fmt(f),
293 Self::SystemName(tlv) => tlv.fmt(f),
294 Self::SystemDescription(tlv) => tlv.fmt(f),
295 Self::SystemCapabilities(tlv) => tlv.fmt(f),
296 Self::ManagementAddress(tlv) => tlv.fmt(f),
297 Self::OrganizationSpecific(tlv) => tlv.fmt(f),
298 Self::UnknownTLV(tlv) => tlv.fmt(f),
299 Self::EndOfLLDPPDU() => write!(f, "End of LLDPPDU"),
300 }
301 }
302}
303
304#[derive(Debug, Eq, PartialEq)]
305pub struct UnknownTlv {
306 ty: u8,
307 payload: Vec<u8>,
308}
309
310impl Serialise for UnknownTlv {
311 fn to_wire(&self) -> Result<Vec<u8>, std::io::Error> {
312 let header = LldpTlvHeader {
313 ty: self.ty,
314 length: self.payload.len() as u16,
315 };
316
317 let mut res = header.to_wire()?;
318 res.append(&mut self.payload.clone());
319 Ok(res)
320 }
321}
322
323impl std::fmt::Display for UnknownTlv {
324 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
325 write!(
326 f,
327 "Unknown TLV type: {}, payload: {:02x?}",
328 self.ty, self.payload
329 )
330 }
331}
332
333#[derive(Debug, Eq, PartialEq)]
334pub struct ChassisId {
335 pub r#type: ChassisIdType,
336 pub identifier: Vec<u8>,
337}
338
339impl Serialise for ChassisId {
340 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
341 let mut result: Vec<u8> = Vec::new();
342 result.append(&mut self.r#type.to_wire()?);
343 result.append(&mut self.identifier.clone());
344 Ok(result)
345 }
346}
347
348impl Deserialise for ChassisId {
349 fn from_wire(
350 buf: &mut pktparser::Buffer<'_>,
351 ) -> std::result::Result<Self, pktparser::ParseError> {
352 let subtype = ChassisIdType::from_wire(buf)?;
353
354 let identifier: Vec<u8> = buf
355 .get_vec(buf.remaining())
356 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
357
358 Ok(ChassisId {
359 r#type: subtype,
360 identifier,
361 })
362 }
363}
364
365impl std::fmt::Display for ChassisId {
366 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
367 write!(
368 f,
369 "ChassisID type: {} value: {:02x?}",
370 self.r#type, self.identifier
371 )
372 }
373}
374
375#[derive(Debug, Eq, PartialEq)]
376pub enum ChassisIdType {
377 ChassisComponent,
378 InterfaceAlias,
379 PortComponent,
380 MacAddress,
381 NetworkAddress,
382 InterfaceName,
383 Local,
384}
385
386impl Deserialise for ChassisIdType {
387 fn from_wire(
388 buf: &mut pktparser::Buffer<'_>,
389 ) -> std::result::Result<ChassisIdType, pktparser::ParseError> {
390 Ok(
391 match buf
392 .get_u8()
393 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?
394 {
395 1 => Self::ChassisComponent,
396 2 => Self::InterfaceAlias,
397 3 => Self::PortComponent,
398 4 => Self::MacAddress,
399 5 => Self::NetworkAddress,
400 6 => Self::InterfaceName,
401 7 => Self::Local,
402 other => {
403 return Err(pktparser::ParseError::InvalidArgument(format!(
404 "Unknown ChassisIDType {}",
405 other
406 )));
407 }
408 },
409 )
410 }
411}
412
413impl Serialise for ChassisIdType {
414 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
415 Ok(match self {
416 Self::ChassisComponent => vec![1],
417 Self::InterfaceAlias => vec![2],
418 Self::PortComponent => vec![3],
419 Self::MacAddress => vec![4],
420 Self::NetworkAddress => vec![5],
421 Self::InterfaceName => vec![6],
422 Self::Local => vec![7],
423 })
424 }
425}
426
427impl std::fmt::Display for ChassisIdType {
428 fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
429 match self {
430 Self::ChassisComponent => write!(f, "ChassisComponent"),
431 Self::InterfaceAlias => write!(f, "InterfaceAlias"),
432 Self::PortComponent => write!(f, "PortComponent"),
433 Self::MacAddress => write!(f, "MacAddress"),
434 Self::NetworkAddress => write!(f, "NetworkAddress"),
435 Self::InterfaceName => write!(f, "InterfaceName"),
436 Self::Local => write!(f, "Local"),
437 }
438 }
439}
440
441#[derive(Debug, Eq, PartialEq)]
442pub struct PortId {
443 pub r#type: PortIdType,
444 pub identifier: Vec<u8>,
445}
446
447impl Deserialise for PortId {
448 fn from_wire(
449 buf: &mut pktparser::Buffer<'_>,
450 ) -> std::result::Result<Self, pktparser::ParseError> {
451 let subtype = PortIdType::from_wire(buf)?;
452
453 let identifier: Vec<u8> = buf
454 .get_vec(buf.remaining())
455 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
456
457 Ok(PortId {
458 r#type: subtype,
459 identifier,
460 })
461 }
462}
463
464impl Serialise for PortId {
465 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
466 let mut result = Vec::new();
467 result.append(&mut self.r#type.to_wire()?);
468 result.append(&mut self.identifier.clone());
469 Ok(result)
470 }
471}
472
473impl std::fmt::Display for PortId {
474 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
475 write!(
477 f,
478 "PortID type: {} value: {:02x?}",
479 self.r#type, self.identifier
480 )
481 }
482}
483
484#[derive(Debug, PartialEq, Eq)]
485pub enum PortIdType {
486 InterfaceAlias,
487 PortComponent,
488 MacAddress,
489 NetworkAddress,
490 InterfaceName,
491 AgentCircuitID,
492 Local,
493}
494
495impl Deserialise for PortIdType {
496 fn from_wire(
497 buf: &mut pktparser::Buffer<'_>,
498 ) -> std::result::Result<Self, pktparser::ParseError> {
499 Ok(
500 match buf
501 .get_u8()
502 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?
503 {
504 1 => Self::InterfaceAlias,
505 2 => Self::PortComponent,
506 3 => Self::MacAddress,
507 4 => Self::NetworkAddress,
508 5 => Self::InterfaceName,
509 6 => Self::AgentCircuitID,
510 7 => Self::Local,
511 other => {
512 return Err(pktparser::ParseError::InvalidArgument(format!(
513 "Unknown PortIDType: {}",
514 other
515 )));
516 }
517 },
518 )
519 }
520}
521
522impl Serialise for PortIdType {
523 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
524 Ok(match self {
525 Self::InterfaceAlias => vec![1],
526 Self::PortComponent => vec![2],
527 Self::MacAddress => vec![3],
528 Self::NetworkAddress => vec![4],
529 Self::InterfaceName => vec![5],
530 Self::AgentCircuitID => vec![6],
531 Self::Local => vec![7],
532 })
533 }
534}
535
536impl std::fmt::Display for PortIdType {
537 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
538 match self {
539 Self::InterfaceAlias => write!(f, "InterfaceAlias"),
540 Self::PortComponent => write!(f, "PortComponent"),
541 Self::MacAddress => write!(f, "MacAddress"),
542 Self::NetworkAddress => write!(f, "NetworkAddress"),
543 Self::InterfaceName => write!(f, "InterfaceName"),
544 Self::AgentCircuitID => write!(f, "AgentCircuitID"),
545 Self::Local => write!(f, "Local"),
546 }
547 }
548}
549
550#[derive(Debug, Eq, PartialEq)]
551pub struct Ttl(u16);
552
553impl Deserialise for Ttl {
554 fn from_wire(
555 buf: &mut pktparser::Buffer<'_>,
556 ) -> std::result::Result<Self, pktparser::ParseError> {
557 if buf.remaining() != 2 {
558 return Err(pktparser::ParseError::InvalidArgument(format!(
559 "TTL TLV length must be 2 but got {}",
560 buf.remaining(),
561 )));
562 }
563
564 let ttl = buf
565 .get_be16()
566 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
567 Ok(Ttl(ttl))
568 }
569}
570
571impl Serialise for Ttl {
572 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
573 let mut result = Vec::new();
574 WriteBytesExt::write_u16::<BigEndian>(&mut result, self.0)?;
575 Ok(result)
576 }
577}
578
579impl std::fmt::Display for Ttl {
580 fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
581 write!(f, "TTL: {} seconds", self.0)
582 }
583}
584
585#[derive(Debug, Eq, PartialEq)]
586pub struct PortDescription {
587 pub description: String,
588}
589
590impl Deserialise for PortDescription {
591 fn from_wire(
592 buf: &mut pktparser::Buffer<'_>,
593 ) -> std::result::Result<Self, pktparser::ParseError> {
594 let description: String = String::from_utf8(
595 buf.get_vec(buf.remaining())
596 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?,
597 )
598 .map_err(|e| pktparser::ParseError::InvalidArgument(e.to_string()))?;
599
600 Ok(PortDescription { description })
601 }
602}
603
604impl Serialise for PortDescription {
605 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
606 Ok(self.description.as_bytes().to_vec())
607 }
608}
609
610impl std::fmt::Display for PortDescription {
611 fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
612 write!(f, "PortDescription: {}", self.description)
613 }
614}
615
616#[derive(Debug, PartialEq, Eq)]
617pub struct SystemName(String);
618
619impl Deserialise for SystemName {
620 fn from_wire(
621 buf: &mut pktparser::Buffer<'_>,
622 ) -> std::result::Result<Self, pktparser::ParseError> {
623 let system_name: String = String::from_utf8(
624 buf.get_vec(buf.remaining())
625 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?,
626 )
627 .map_err(|e| pktparser::ParseError::InvalidArgument(e.to_string()))?;
628
629 Ok(SystemName(system_name))
630 }
631}
632
633impl Serialise for SystemName {
634 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
635 Ok(self.0.as_bytes().to_vec())
636 }
637}
638
639impl std::fmt::Display for SystemName {
640 fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
641 write!(f, "SystemName: {}", self.0)
642 }
643}
644
645#[derive(Debug, Eq, PartialEq)]
646pub struct SystemDescription(String);
647
648impl Deserialise for SystemDescription {
649 fn from_wire(
650 buf: &mut pktparser::Buffer<'_>,
651 ) -> std::result::Result<Self, pktparser::ParseError> {
652 let system_description: String = String::from_utf8(
653 buf.get_vec(buf.remaining())
654 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?,
655 )
656 .map_err(|e| pktparser::ParseError::InvalidArgument(e.to_string()))?;
657
658 Ok(SystemDescription(system_description))
659 }
660}
661
662impl Serialise for SystemDescription {
663 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
664 Ok(self.0.as_bytes().to_vec())
665 }
666}
667
668impl std::fmt::Display for SystemDescription {
669 fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
670 write!(f, "SystemDescription: {}", self.0)
671 }
672}
673
674#[derive(Debug, Eq, PartialEq)]
675pub struct SystemCapabilities {
676 pub sys_cap: u16,
677 pub enabled_cap: u16,
678}
679
680impl Deserialise for SystemCapabilities {
681 fn from_wire(
682 buf: &mut pktparser::Buffer<'_>,
683 ) -> std::result::Result<Self, pktparser::ParseError> {
684 if buf.remaining() != 4 {
685 return Err(pktparser::ParseError::InvalidArgument(format!(
686 "SystemCapabilities TLV length must be 4 but got {}",
687 buf.remaining(),
688 )));
689 }
690
691 let sys_cap = buf
692 .get_be16()
693 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
694 let enabled_cap = buf
695 .get_be16()
696 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
697
698 Ok(SystemCapabilities {
699 sys_cap,
700 enabled_cap,
701 })
702 }
703}
704
705impl Serialise for SystemCapabilities {
706 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
707 let mut result = Vec::new();
708 WriteBytesExt::write_u16::<BigEndian>(&mut result, self.sys_cap)?;
709 WriteBytesExt::write_u16::<BigEndian>(&mut result, self.enabled_cap)?;
710 Ok(result)
711 }
712}
713
714impl std::fmt::Display for SystemCapabilities {
715 fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
716 write!(
717 f,
718 "SystemCapabilities system: {}, enabled: {}",
719 self.sys_cap, self.enabled_cap
720 )
721 }
722}
723
724#[derive(Debug, Eq, PartialEq)]
725pub struct ManagementAddress {
726 pub address: Vec<u8>,
727 pub address_family: u8,
729 pub numbering_subtype: u8,
730 pub if_number: u32,
731 pub oid: Vec<u8>,
732}
733
734impl Deserialise for ManagementAddress {
735 fn from_wire(
736 buf: &mut pktparser::Buffer<'_>,
737 ) -> std::result::Result<Self, pktparser::ParseError> {
738 let mgmt_addr_len = (buf
739 .get_u8()
740 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?)
741 - 1; let mgmt_addr_af = buf
743 .get_u8()
744 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
745 if !(1..=32).contains(&mgmt_addr_len) {
746 return Err(pktparser::ParseError::InvalidArgument(format!(
747 "{} outside of valid range for mgmt_addr_len",
748 mgmt_addr_len
749 )));
750 }
751 let mgmt_addr = buf
752 .get_bytes(mgmt_addr_len.into())
753 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
754
755 let numbering_subtype: u8 = buf
756 .get_u8()
757 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
758 let if_number = buf
759 .get_be32()
760 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
761
762 let oid_len = buf
763 .get_u8()
764 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
765 let oid = buf
766 .get_bytes(oid_len.into())
767 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?
768 .to_vec();
769
770 Ok(ManagementAddress {
771 address: mgmt_addr.to_vec(),
772 address_family: mgmt_addr_af,
773 numbering_subtype,
774 if_number,
775 oid,
776 })
777 }
778}
779
780impl Serialise for ManagementAddress {
781 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
782 let mut payload: Vec<u8> = Vec::new();
783 if self.address.len() > u8::MAX.into() {
784 return Err(std::io::Error::new(
785 std::io::ErrorKind::InvalidData,
786 format!(
787 "management address too long: got {} but size is u8",
788 self.address.len()
789 ),
790 ));
791 }
792 payload.push(self.address.len() as u8);
793 payload.push(self.address_family);
794 payload.append(&mut self.address.clone());
795 payload.push(self.numbering_subtype);
796 WriteBytesExt::write_u32::<BigEndian>(&mut payload, self.if_number)?;
797 if self.oid.len() > u8::MAX.into() {
798 return Err(std::io::Error::new(
799 std::io::ErrorKind::InvalidData,
800 format!("oid too long: got {} but size is u8", self.oid.len()),
801 ));
802 }
803 payload.push(self.oid.len() as u8);
804 payload.append(&mut self.oid.clone());
805
806 Ok(payload)
807 }
808}
809
810impl std::fmt::Display for ManagementAddress {
811 fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
812 write!(
813 f,
814 "ManagementAddress address: {:02x?}, af: {}, numbering_subtype: {}, if_number: {}, oid: {:?}",
815 self.address, self.address_family, self.numbering_subtype, self.if_number, self.oid
816 )
817 }
818}
819
820#[derive(Debug, Eq, PartialEq)]
821pub struct OrganizationSpecific {
822 pub oui: [u8; 3],
823 pub subtype: u8,
824 pub value: Vec<u8>,
825}
826
827impl Deserialise for OrganizationSpecific {
828 fn from_wire(
829 buf: &mut pktparser::Buffer<'_>,
830 ) -> std::result::Result<Self, pktparser::ParseError> {
831 let oui = buf
832 .get_bytes(3)
833 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?
834 .to_vec();
835 let subtype = buf
836 .get_u8()
837 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
838 let value = buf
839 .get_bytes(buf.remaining())
840 .ok_or(pktparser::ParseError::UnexpectedEndOfInput)?;
841
842 Ok(OrganizationSpecific {
843 oui: oui
844 .try_into()
845 .expect("Error in converting Vec of len 3 to slice of len 3"),
846 subtype,
847 value: value.to_vec(),
848 })
849 }
850}
851
852impl Serialise for OrganizationSpecific {
853 fn to_wire(&self) -> std::result::Result<Vec<u8>, std::io::Error> {
854 let mut payload = Vec::new();
855 payload.append(&mut self.oui.to_vec());
856 payload.push(self.subtype);
857 payload.append(&mut self.value.clone());
858 Ok(payload)
859 }
860}
861
862impl std::fmt::Display for OrganizationSpecific {
863 fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
864 write!(
865 f,
866 "OrganizationSpecific oui: {:02x?} subtype: {}, value: {:02x?}",
867 self.oui, self.subtype, self.value
868 )
869 }
870}
871
872#[cfg(test)]
873mod tests {
874 use super::*;
875
876 #[test]
877 fn parse_chassis_tlv() {
878 let bytes = vec![0x02, 0x07, 0x04, 0x8c, 0x1f, 0x64, 0xac, 0xe0, 0x00];
879 let parsed = LldpTlv::from_wire(&mut pktparser::Buffer::new(&bytes)).unwrap();
880 assert_eq!(
881 "ChassisID type: MacAddress value: [8c, 1f, 64, ac, e0, 00]",
882 parsed.to_string()
883 );
884 let reserialized = parsed.to_wire().unwrap();
885 assert_eq!(reserialized, bytes);
886 }
887
888 #[test]
889 fn parse_portid_tlv() {
890 let bytes = vec![
891 0x04, 0x0d, 0x01, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x53,
892 0x31,
893 ];
894 let parsed = LldpTlv::from_wire(&mut pktparser::Buffer::new(&bytes)).unwrap();
895 assert_eq!(
896 "PortID type: InterfaceAlias value: [55, 70, 6c, 69, 6e, 6b, 20, 74, 6f, 20, 53, 31]",
897 parsed.to_string()
898 );
899 let reserialized = parsed.to_wire().unwrap();
900 assert_eq!(reserialized, bytes);
901 }
902
903 #[test]
904 fn parse_ttl_tlv() {
905 let bytes = vec![0x06, 0x02, 0x00, 0x78];
906 let parsed = LldpTlv::from_wire(&mut pktparser::Buffer::new(&bytes)).unwrap();
907 assert_eq!("TTL: 120 seconds", parsed.to_string());
908 let reserialized = parsed.to_wire().unwrap();
909 assert_eq!(reserialized, bytes);
910 }
911
912 #[test]
913 fn parse_system_name_tlv() {
914 let bytes = vec![
915 0x0a, 0x0c, 0x53, 0x32, 0x2e, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,
916 ];
917 let parsed = LldpTlv::from_wire(&mut pktparser::Buffer::new(&bytes)).unwrap();
918 assert_eq!("SystemName: S2.cisco.com", parsed.to_string());
919 let reserialized = parsed.to_wire().unwrap();
920 assert_eq!(reserialized, bytes);
921 }
922
923 #[test]
924 fn parse_system_description_tlv() {
925 let bytes = vec![
926 0x0c, 0xbe, 0x43, 0x69, 0x73, 0x63, 0x6f, 0x20, 0x49, 0x4f, 0x53, 0x20, 0x53, 0x6f,
927 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2c, 0x20, 0x43, 0x33, 0x35, 0x36, 0x30, 0x20,
928 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x28, 0x43, 0x33, 0x35, 0x36,
929 0x30, 0x2d, 0x41, 0x44, 0x56, 0x49, 0x50, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45,
930 0x53, 0x4b, 0x39, 0x2d, 0x4d, 0x29, 0x2c, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
931 0x6e, 0x20, 0x31, 0x32, 0x2e, 0x32, 0x28, 0x34, 0x34, 0x29, 0x53, 0x45, 0x2c, 0x20,
932 0x52, 0x45, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x20, 0x53, 0x4f, 0x46, 0x54, 0x57, 0x41,
933 0x52, 0x45, 0x20, 0x28, 0x66, 0x63, 0x31, 0x29, 0x0a, 0x43, 0x6f, 0x70, 0x79, 0x72,
934 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x38, 0x36, 0x2d,
935 0x32, 0x30, 0x30, 0x38, 0x20, 0x62, 0x79, 0x20, 0x43, 0x69, 0x73, 0x63, 0x6f, 0x20,
936 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a,
937 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x53, 0x61, 0x74, 0x20, 0x30,
938 0x35, 0x2d, 0x4a, 0x61, 0x6e, 0x2d, 0x30, 0x38, 0x20, 0x30, 0x30, 0x3a, 0x31, 0x35,
939 0x20, 0x62, 0x79, 0x20, 0x77, 0x65, 0x69, 0x6c, 0x69, 0x75,
940 ];
941 let parsed = LldpTlv::from_wire(&mut pktparser::Buffer::new(&bytes)).unwrap();
942 assert_eq!(
943 "SystemDescription: Cisco IOS Software, C3560 Software (C3560-ADVIPSERVICESK9-M), Version 12.2(44)SE, RELEASE SOFTWARE (fc1)\nCopyright (c) 1986-2008 by Cisco Systems, Inc.\nCompiled Sat 05-Jan-08 00:15 by weiliu",
944 parsed.to_string()
945 );
946 let reserialized = parsed.to_wire().unwrap();
947 assert_eq!(reserialized, bytes);
948 }
949
950 #[test]
951 fn parse_port_description_tlv() {
952 let bytes = vec![
953 0x08, 0x13, 0x47, 0x69, 0x67, 0x61, 0x62, 0x69, 0x74, 0x45, 0x74, 0x68, 0x65, 0x72,
954 0x6e, 0x65, 0x74, 0x30, 0x2f, 0x31, 0x33,
955 ];
956 let parsed = LldpTlv::from_wire(&mut pktparser::Buffer::new(&bytes)).unwrap();
957 assert_eq!("PortDescription: GigabitEthernet0/13", parsed.to_string());
958 let reserialized = parsed.to_wire().unwrap();
959 assert_eq!(reserialized, bytes);
960 }
961
962 #[test]
963 fn parse_capabilities_tlv() {
964 let bytes = vec![0x0e, 0x04, 0x00, 0x14, 0x00, 0x04];
965 let parsed = LldpTlv::from_wire(&mut pktparser::Buffer::new(&bytes)).unwrap();
966 assert_eq!(
967 "SystemCapabilities system: 20, enabled: 4",
968 parsed.to_string()
969 );
970 let reserialized = parsed.to_wire().unwrap();
971 assert_eq!(reserialized, bytes);
972 }
973
974 #[test]
975 fn parse_organization_specific() {
976 let bytes = vec![
977 0xfe, 0x09, 0x00, 0x12, 0x0f, 0x01, 0x03, 0xc0, 0x36, 0x00, 0x10,
978 ];
979 let parsed = LldpTlv::from_wire(&mut pktparser::Buffer::new(&bytes)).unwrap();
980 assert_eq!(
981 "OrganizationSpecific oui: [00, 12, 0f] subtype: 1, value: [03, c0, 36, 00, 10]",
982 parsed.to_string()
983 );
984 let reserialized = parsed.to_wire().unwrap();
985 assert_eq!(reserialized, bytes);
986 }
987
988 #[test]
989 fn parse_unknown_tlv() {
990 let bytes = vec![0xaa, 0x01, 0x42];
991 let parsed = LldpTlv::from_wire(&mut pktparser::Buffer::new(&bytes)).unwrap();
992 assert_eq!("Unknown TLV type: 85, payload: [42]", parsed.to_string());
993 let reserialized = parsed.to_wire().unwrap();
994 assert_eq!(reserialized, bytes);
995 }
996
997 #[test]
998 fn parse_lldp_packet() {
999 let bytes = vec![
1000 0x02, 0x07, 0x04, 0x00, 0x19, 0x2f, 0xa7, 0xb2, 0x8d, 0x04, 0x0d, 0x01, 0x55, 0x70,
1001 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x53, 0x31, 0x06, 0x02, 0x00, 0x78,
1002 0x0a, 0x0c, 0x53, 0x32, 0x2e, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,
1003 0x0c, 0xbe, 0x43, 0x69, 0x73, 0x63, 0x6f, 0x20, 0x49, 0x4f, 0x53, 0x20, 0x53, 0x6f,
1004 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2c, 0x20, 0x43, 0x33, 0x35, 0x36, 0x30, 0x20,
1005 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x28, 0x43, 0x33, 0x35, 0x36,
1006 0x30, 0x2d, 0x41, 0x44, 0x56, 0x49, 0x50, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45,
1007 0x53, 0x4b, 0x39, 0x2d, 0x4d, 0x29, 0x2c, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
1008 0x6e, 0x20, 0x31, 0x32, 0x2e, 0x32, 0x28, 0x34, 0x34, 0x29, 0x53, 0x45, 0x2c, 0x20,
1009 0x52, 0x45, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x20, 0x53, 0x4f, 0x46, 0x54, 0x57, 0x41,
1010 0x52, 0x45, 0x20, 0x28, 0x66, 0x63, 0x31, 0x29, 0x0a, 0x43, 0x6f, 0x70, 0x79, 0x72,
1011 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x38, 0x36, 0x2d,
1012 0x32, 0x30, 0x30, 0x38, 0x20, 0x62, 0x79, 0x20, 0x43, 0x69, 0x73, 0x63, 0x6f, 0x20,
1013 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a,
1014 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x53, 0x61, 0x74, 0x20, 0x30,
1015 0x35, 0x2d, 0x4a, 0x61, 0x6e, 0x2d, 0x30, 0x38, 0x20, 0x30, 0x30, 0x3a, 0x31, 0x35,
1016 0x20, 0x62, 0x79, 0x20, 0x77, 0x65, 0x69, 0x6c, 0x69, 0x75, 0x08, 0x13, 0x47, 0x69,
1017 0x67, 0x61, 0x62, 0x69, 0x74, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x30,
1018 0x2f, 0x31, 0x33, 0x0e, 0x04, 0x00, 0x14, 0x00, 0x04, 0xfe, 0x06, 0x00, 0x80, 0xc2,
1019 0x01, 0x00, 0x01, 0xfe, 0x09, 0x00, 0x12, 0x0f, 0x01, 0x03, 0xc0, 0x36, 0x00, 0x10,
1020 0x00, 0x00,
1021 ];
1022 let parsed = LldpPacket::from_wire(&mut pktparser::Buffer::new(&bytes)).unwrap();
1023 assert_eq!(
1024 "LLDP [\n\tChassisID type: MacAddress value: [00, 19, 2f, a7, b2, 8d]\n\tPortID type: InterfaceAlias value: [55, 70, 6c, 69, 6e, 6b, 20, 74, 6f, 20, 53, 31]\n\tTTL: 120 seconds\n\tSystemName: S2.cisco.com\n\tSystemDescription: Cisco IOS Software, C3560 Software (C3560-ADVIPSERVICESK9-M), Version 12.2(44)SE, RELEASE SOFTWARE (fc1)\nCopyright (c) 1986-2008 by Cisco Systems, Inc.\nCompiled Sat 05-Jan-08 00:15 by weiliu\n\tPortDescription: GigabitEthernet0/13\n\tSystemCapabilities system: 20, enabled: 4\n\tOrganizationSpecific oui: [00, 80, c2] subtype: 1, value: [00, 01]\n\tOrganizationSpecific oui: [00, 12, 0f] subtype: 1, value: [03, c0, 36, 00, 10]\n\tEnd of LLDPPDU\n]",
1025 parsed.to_string()
1026 );
1027 let reserialized = parsed.to_wire().unwrap();
1028 assert_eq!(reserialized, bytes);
1029 }
1030
1031 #[test]
1032 fn parse2() {
1033 let bytes = [
1034 1, 128, 194, 0, 0, 14, 32, 12, 200, 58, 251, 201, 136, 204, 2, 7, 4, 32, 12, 200, 58, 251, 199, 4, 3, 7, 103, 50, 6, 2, 0, 120, 8, 0, 10, 7, 115, 119, 105, 116, 99, 104, 49, 12, 28, 78, 101, 116, 103, 101, 97, 114, 32, 71, 105, 103, 97, 98, 105, 116, 32, 83,
1043 109, 97, 114, 116, 32, 83, 119, 105, 116, 99, 104, 14, 4, 0, 4, 0, 4, 16, 20, 5, 1, 192, 168, 0, 238, 2, 0, 0, 0, 13, 8, 98, 114, 111, 97, 100, 99, 111,
1046 109, 0, 0, ];
1049 let _parsed = LldpPacket::from_wire(&mut pktparser::Buffer::new(&bytes[14..])).unwrap();
1050 }
1051}