| // Copyright 2012 Google, Inc. All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style license |
| // that can be found in the LICENSE file in the root of the source |
| // tree. |
| |
| package layers |
| |
| import ( |
| "encoding/binary" |
| "errors" |
| "fmt" |
| |
| "github.com/google/gopacket" |
| ) |
| |
| // LLDPTLVType is the type of each TLV value in a LinkLayerDiscovery packet. |
| type LLDPTLVType byte |
| |
| const ( |
| LLDPTLVEnd LLDPTLVType = 0 |
| LLDPTLVChassisID LLDPTLVType = 1 |
| LLDPTLVPortID LLDPTLVType = 2 |
| LLDPTLVTTL LLDPTLVType = 3 |
| LLDPTLVPortDescription LLDPTLVType = 4 |
| LLDPTLVSysName LLDPTLVType = 5 |
| LLDPTLVSysDescription LLDPTLVType = 6 |
| LLDPTLVSysCapabilities LLDPTLVType = 7 |
| LLDPTLVMgmtAddress LLDPTLVType = 8 |
| LLDPTLVOrgSpecific LLDPTLVType = 127 |
| ) |
| |
| // LinkLayerDiscoveryValue is a TLV value inside a LinkLayerDiscovery packet layer. |
| type LinkLayerDiscoveryValue struct { |
| Type LLDPTLVType |
| Length uint16 |
| Value []byte |
| } |
| |
| func (c *LinkLayerDiscoveryValue) len() int { |
| return 0 |
| } |
| |
| // LLDPChassisIDSubType specifies the value type for a single LLDPChassisID.ID |
| type LLDPChassisIDSubType byte |
| |
| // LLDP Chassis Types |
| const ( |
| LLDPChassisIDSubTypeReserved LLDPChassisIDSubType = 0 |
| LLDPChassisIDSubTypeChassisComp LLDPChassisIDSubType = 1 |
| LLDPChassisIDSubtypeIfaceAlias LLDPChassisIDSubType = 2 |
| LLDPChassisIDSubTypePortComp LLDPChassisIDSubType = 3 |
| LLDPChassisIDSubTypeMACAddr LLDPChassisIDSubType = 4 |
| LLDPChassisIDSubTypeNetworkAddr LLDPChassisIDSubType = 5 |
| LLDPChassisIDSubtypeIfaceName LLDPChassisIDSubType = 6 |
| LLDPChassisIDSubTypeLocal LLDPChassisIDSubType = 7 |
| ) |
| |
| type LLDPChassisID struct { |
| Subtype LLDPChassisIDSubType |
| ID []byte |
| } |
| |
| func (c *LLDPChassisID) serialize() []byte { |
| |
| var buf = make([]byte, c.serializedLen()) |
| idLen := uint16(LLDPTLVChassisID)<<9 | uint16(len(c.ID)+1) //id should take 7 bits, length should take 9 bits, +1 for subtype |
| binary.BigEndian.PutUint16(buf[0:2], idLen) |
| buf[2] = byte(c.Subtype) |
| copy(buf[3:], c.ID) |
| return buf |
| } |
| |
| func (c *LLDPChassisID) serializedLen() int { |
| return len(c.ID) + 3 // +2 for id and length, +1 for subtype |
| } |
| |
| // LLDPPortIDSubType specifies the value type for a single LLDPPortID.ID |
| type LLDPPortIDSubType byte |
| |
| // LLDP PortID types |
| const ( |
| LLDPPortIDSubtypeReserved LLDPPortIDSubType = 0 |
| LLDPPortIDSubtypeIfaceAlias LLDPPortIDSubType = 1 |
| LLDPPortIDSubtypePortComp LLDPPortIDSubType = 2 |
| LLDPPortIDSubtypeMACAddr LLDPPortIDSubType = 3 |
| LLDPPortIDSubtypeNetworkAddr LLDPPortIDSubType = 4 |
| LLDPPortIDSubtypeIfaceName LLDPPortIDSubType = 5 |
| LLDPPortIDSubtypeAgentCircuitID LLDPPortIDSubType = 6 |
| LLDPPortIDSubtypeLocal LLDPPortIDSubType = 7 |
| ) |
| |
| type LLDPPortID struct { |
| Subtype LLDPPortIDSubType |
| ID []byte |
| } |
| |
| func (c *LLDPPortID) serialize() []byte { |
| |
| var buf = make([]byte, c.serializedLen()) |
| idLen := uint16(LLDPTLVPortID)<<9 | uint16(len(c.ID)+1) //id should take 7 bits, length should take 9 bits, +1 for subtype |
| binary.BigEndian.PutUint16(buf[0:2], idLen) |
| buf[2] = byte(c.Subtype) |
| copy(buf[3:], c.ID) |
| return buf |
| } |
| |
| func (c *LLDPPortID) serializedLen() int { |
| return len(c.ID) + 3 // +2 for id and length, +1 for subtype |
| } |
| |
| // LinkLayerDiscovery is a packet layer containing the LinkLayer Discovery Protocol. |
| // See http:http://standards.ieee.org/getieee802/download/802.1AB-2009.pdf |
| // ChassisID, PortID and TTL are mandatory TLV's. Other values can be decoded |
| // with DecodeValues() |
| type LinkLayerDiscovery struct { |
| BaseLayer |
| ChassisID LLDPChassisID |
| PortID LLDPPortID |
| TTL uint16 |
| Values []LinkLayerDiscoveryValue |
| } |
| |
| type IEEEOUI uint32 |
| |
| // http://standards.ieee.org/develop/regauth/oui/oui.txt |
| const ( |
| IEEEOUI8021 IEEEOUI = 0x0080c2 |
| IEEEOUI8023 IEEEOUI = 0x00120f |
| IEEEOUI80211 IEEEOUI = 0x000fac |
| IEEEOUI8021Qbg IEEEOUI = 0x0013BF |
| IEEEOUICisco2 IEEEOUI = 0x000142 |
| IEEEOUIMedia IEEEOUI = 0x0012bb // TR-41 |
| IEEEOUIProfinet IEEEOUI = 0x000ecf |
| IEEEOUIDCBX IEEEOUI = 0x001b21 |
| ) |
| |
| // LLDPOrgSpecificTLV is an Organisation-specific TLV |
| type LLDPOrgSpecificTLV struct { |
| OUI IEEEOUI |
| SubType uint8 |
| Info []byte |
| } |
| |
| // LLDPCapabilities Types |
| const ( |
| LLDPCapsOther uint16 = 1 << 0 |
| LLDPCapsRepeater uint16 = 1 << 1 |
| LLDPCapsBridge uint16 = 1 << 2 |
| LLDPCapsWLANAP uint16 = 1 << 3 |
| LLDPCapsRouter uint16 = 1 << 4 |
| LLDPCapsPhone uint16 = 1 << 5 |
| LLDPCapsDocSis uint16 = 1 << 6 |
| LLDPCapsStationOnly uint16 = 1 << 7 |
| LLDPCapsCVLAN uint16 = 1 << 8 |
| LLDPCapsSVLAN uint16 = 1 << 9 |
| LLDPCapsTmpr uint16 = 1 << 10 |
| ) |
| |
| // LLDPCapabilities represents the capabilities of a device |
| type LLDPCapabilities struct { |
| Other bool |
| Repeater bool |
| Bridge bool |
| WLANAP bool |
| Router bool |
| Phone bool |
| DocSis bool |
| StationOnly bool |
| CVLAN bool |
| SVLAN bool |
| TMPR bool |
| } |
| |
| type LLDPSysCapabilities struct { |
| SystemCap LLDPCapabilities |
| EnabledCap LLDPCapabilities |
| } |
| |
| type IANAAddressFamily byte |
| |
| // LLDP Management Address Subtypes |
| // http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml |
| const ( |
| IANAAddressFamilyReserved IANAAddressFamily = 0 |
| IANAAddressFamilyIPV4 IANAAddressFamily = 1 |
| IANAAddressFamilyIPV6 IANAAddressFamily = 2 |
| IANAAddressFamilyNSAP IANAAddressFamily = 3 |
| IANAAddressFamilyHDLC IANAAddressFamily = 4 |
| IANAAddressFamilyBBN1822 IANAAddressFamily = 5 |
| IANAAddressFamily802 IANAAddressFamily = 6 |
| IANAAddressFamilyE163 IANAAddressFamily = 7 |
| IANAAddressFamilyE164 IANAAddressFamily = 8 |
| IANAAddressFamilyF69 IANAAddressFamily = 9 |
| IANAAddressFamilyX121 IANAAddressFamily = 10 |
| IANAAddressFamilyIPX IANAAddressFamily = 11 |
| IANAAddressFamilyAtalk IANAAddressFamily = 12 |
| IANAAddressFamilyDecnet IANAAddressFamily = 13 |
| IANAAddressFamilyBanyan IANAAddressFamily = 14 |
| IANAAddressFamilyE164NSAP IANAAddressFamily = 15 |
| IANAAddressFamilyDNS IANAAddressFamily = 16 |
| IANAAddressFamilyDistname IANAAddressFamily = 17 |
| IANAAddressFamilyASNumber IANAAddressFamily = 18 |
| IANAAddressFamilyXTPIPV4 IANAAddressFamily = 19 |
| IANAAddressFamilyXTPIPV6 IANAAddressFamily = 20 |
| IANAAddressFamilyXTP IANAAddressFamily = 21 |
| IANAAddressFamilyFcWWPN IANAAddressFamily = 22 |
| IANAAddressFamilyFcWWNN IANAAddressFamily = 23 |
| IANAAddressFamilyGWID IANAAddressFamily = 24 |
| IANAAddressFamilyL2VPN IANAAddressFamily = 25 |
| ) |
| |
| type LLDPInterfaceSubtype byte |
| |
| // LLDP Interface Subtypes |
| const ( |
| LLDPInterfaceSubtypeUnknown LLDPInterfaceSubtype = 1 |
| LLDPInterfaceSubtypeifIndex LLDPInterfaceSubtype = 2 |
| LLDPInterfaceSubtypeSysPort LLDPInterfaceSubtype = 3 |
| ) |
| |
| type LLDPMgmtAddress struct { |
| Subtype IANAAddressFamily |
| Address []byte |
| InterfaceSubtype LLDPInterfaceSubtype |
| InterfaceNumber uint32 |
| OID string |
| } |
| |
| // LinkLayerDiscoveryInfo represents the decoded details for a set of LinkLayerDiscoveryValues |
| // Organisation-specific TLV's can be decoded using the various Decode() methods |
| type LinkLayerDiscoveryInfo struct { |
| BaseLayer |
| PortDescription string |
| SysName string |
| SysDescription string |
| SysCapabilities LLDPSysCapabilities |
| MgmtAddress LLDPMgmtAddress |
| OrgTLVs []LLDPOrgSpecificTLV // Private TLVs |
| Unknown []LinkLayerDiscoveryValue // undecoded TLVs |
| } |
| |
| /// IEEE 802.1 TLV Subtypes |
| const ( |
| LLDP8021SubtypePortVLANID uint8 = 1 |
| LLDP8021SubtypeProtocolVLANID uint8 = 2 |
| LLDP8021SubtypeVLANName uint8 = 3 |
| LLDP8021SubtypeProtocolIdentity uint8 = 4 |
| LLDP8021SubtypeVDIUsageDigest uint8 = 5 |
| LLDP8021SubtypeManagementVID uint8 = 6 |
| LLDP8021SubtypeLinkAggregation uint8 = 7 |
| ) |
| |
| // VLAN Port Protocol ID options |
| const ( |
| LLDPProtocolVLANIDCapability byte = 1 << 1 |
| LLDPProtocolVLANIDStatus byte = 1 << 2 |
| ) |
| |
| type PortProtocolVLANID struct { |
| Supported bool |
| Enabled bool |
| ID uint16 |
| } |
| |
| type VLANName struct { |
| ID uint16 |
| Name string |
| } |
| |
| type ProtocolIdentity []byte |
| |
| // LACP options |
| const ( |
| LLDPAggregationCapability byte = 1 << 0 |
| LLDPAggregationStatus byte = 1 << 1 |
| ) |
| |
| // IEEE 802 Link Aggregation parameters |
| type LLDPLinkAggregation struct { |
| Supported bool |
| Enabled bool |
| PortID uint32 |
| } |
| |
| // LLDPInfo8021 represents the information carried in 802.1 Org-specific TLVs |
| type LLDPInfo8021 struct { |
| PVID uint16 |
| PPVIDs []PortProtocolVLANID |
| VLANNames []VLANName |
| ProtocolIdentities []ProtocolIdentity |
| VIDUsageDigest uint32 |
| ManagementVID uint16 |
| LinkAggregation LLDPLinkAggregation |
| } |
| |
| // IEEE 802.3 TLV Subtypes |
| const ( |
| LLDP8023SubtypeMACPHY uint8 = 1 |
| LLDP8023SubtypeMDIPower uint8 = 2 |
| LLDP8023SubtypeLinkAggregation uint8 = 3 |
| LLDP8023SubtypeMTU uint8 = 4 |
| ) |
| |
| // MACPHY options |
| const ( |
| LLDPMACPHYCapability byte = 1 << 0 |
| LLDPMACPHYStatus byte = 1 << 1 |
| ) |
| |
| // From IANA-MAU-MIB (introduced by RFC 4836) - dot3MauType |
| const ( |
| LLDPMAUTypeUnknown uint16 = 0 |
| LLDPMAUTypeAUI uint16 = 1 |
| LLDPMAUType10Base5 uint16 = 2 |
| LLDPMAUTypeFOIRL uint16 = 3 |
| LLDPMAUType10Base2 uint16 = 4 |
| LLDPMAUType10BaseT uint16 = 5 |
| LLDPMAUType10BaseFP uint16 = 6 |
| LLDPMAUType10BaseFB uint16 = 7 |
| LLDPMAUType10BaseFL uint16 = 8 |
| LLDPMAUType10BROAD36 uint16 = 9 |
| LLDPMAUType10BaseT_HD uint16 = 10 |
| LLDPMAUType10BaseT_FD uint16 = 11 |
| LLDPMAUType10BaseFL_HD uint16 = 12 |
| LLDPMAUType10BaseFL_FD uint16 = 13 |
| LLDPMAUType100BaseT4 uint16 = 14 |
| LLDPMAUType100BaseTX_HD uint16 = 15 |
| LLDPMAUType100BaseTX_FD uint16 = 16 |
| LLDPMAUType100BaseFX_HD uint16 = 17 |
| LLDPMAUType100BaseFX_FD uint16 = 18 |
| LLDPMAUType100BaseT2_HD uint16 = 19 |
| LLDPMAUType100BaseT2_FD uint16 = 20 |
| LLDPMAUType1000BaseX_HD uint16 = 21 |
| LLDPMAUType1000BaseX_FD uint16 = 22 |
| LLDPMAUType1000BaseLX_HD uint16 = 23 |
| LLDPMAUType1000BaseLX_FD uint16 = 24 |
| LLDPMAUType1000BaseSX_HD uint16 = 25 |
| LLDPMAUType1000BaseSX_FD uint16 = 26 |
| LLDPMAUType1000BaseCX_HD uint16 = 27 |
| LLDPMAUType1000BaseCX_FD uint16 = 28 |
| LLDPMAUType1000BaseT_HD uint16 = 29 |
| LLDPMAUType1000BaseT_FD uint16 = 30 |
| LLDPMAUType10GBaseX uint16 = 31 |
| LLDPMAUType10GBaseLX4 uint16 = 32 |
| LLDPMAUType10GBaseR uint16 = 33 |
| LLDPMAUType10GBaseER uint16 = 34 |
| LLDPMAUType10GBaseLR uint16 = 35 |
| LLDPMAUType10GBaseSR uint16 = 36 |
| LLDPMAUType10GBaseW uint16 = 37 |
| LLDPMAUType10GBaseEW uint16 = 38 |
| LLDPMAUType10GBaseLW uint16 = 39 |
| LLDPMAUType10GBaseSW uint16 = 40 |
| LLDPMAUType10GBaseCX4 uint16 = 41 |
| LLDPMAUType2BaseTL uint16 = 42 |
| LLDPMAUType10PASS_TS uint16 = 43 |
| LLDPMAUType100BaseBX10D uint16 = 44 |
| LLDPMAUType100BaseBX10U uint16 = 45 |
| LLDPMAUType100BaseLX10 uint16 = 46 |
| LLDPMAUType1000BaseBX10D uint16 = 47 |
| LLDPMAUType1000BaseBX10U uint16 = 48 |
| LLDPMAUType1000BaseLX10 uint16 = 49 |
| LLDPMAUType1000BasePX10D uint16 = 50 |
| LLDPMAUType1000BasePX10U uint16 = 51 |
| LLDPMAUType1000BasePX20D uint16 = 52 |
| LLDPMAUType1000BasePX20U uint16 = 53 |
| LLDPMAUType10GBaseT uint16 = 54 |
| LLDPMAUType10GBaseLRM uint16 = 55 |
| LLDPMAUType1000BaseKX uint16 = 56 |
| LLDPMAUType10GBaseKX4 uint16 = 57 |
| LLDPMAUType10GBaseKR uint16 = 58 |
| LLDPMAUType10_1GBasePRX_D1 uint16 = 59 |
| LLDPMAUType10_1GBasePRX_D2 uint16 = 60 |
| LLDPMAUType10_1GBasePRX_D3 uint16 = 61 |
| LLDPMAUType10_1GBasePRX_U1 uint16 = 62 |
| LLDPMAUType10_1GBasePRX_U2 uint16 = 63 |
| LLDPMAUType10_1GBasePRX_U3 uint16 = 64 |
| LLDPMAUType10GBasePR_D1 uint16 = 65 |
| LLDPMAUType10GBasePR_D2 uint16 = 66 |
| LLDPMAUType10GBasePR_D3 uint16 = 67 |
| LLDPMAUType10GBasePR_U1 uint16 = 68 |
| LLDPMAUType10GBasePR_U3 uint16 = 69 |
| ) |
| |
| // From RFC 3636 - ifMauAutoNegCapAdvertisedBits |
| const ( |
| LLDPMAUPMDOther uint16 = 1 << 15 |
| LLDPMAUPMD10BaseT uint16 = 1 << 14 |
| LLDPMAUPMD10BaseT_FD uint16 = 1 << 13 |
| LLDPMAUPMD100BaseT4 uint16 = 1 << 12 |
| LLDPMAUPMD100BaseTX uint16 = 1 << 11 |
| LLDPMAUPMD100BaseTX_FD uint16 = 1 << 10 |
| LLDPMAUPMD100BaseT2 uint16 = 1 << 9 |
| LLDPMAUPMD100BaseT2_FD uint16 = 1 << 8 |
| LLDPMAUPMDFDXPAUSE uint16 = 1 << 7 |
| LLDPMAUPMDFDXAPAUSE uint16 = 1 << 6 |
| LLDPMAUPMDFDXSPAUSE uint16 = 1 << 5 |
| LLDPMAUPMDFDXBPAUSE uint16 = 1 << 4 |
| LLDPMAUPMD1000BaseX uint16 = 1 << 3 |
| LLDPMAUPMD1000BaseX_FD uint16 = 1 << 2 |
| LLDPMAUPMD1000BaseT uint16 = 1 << 1 |
| LLDPMAUPMD1000BaseT_FD uint16 = 1 << 0 |
| ) |
| |
| // Inverted ifMauAutoNegCapAdvertisedBits if required |
| // (Some manufacturers misinterpreted the spec - |
| // see https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1455) |
| const ( |
| LLDPMAUPMDOtherInv uint16 = 1 << 0 |
| LLDPMAUPMD10BaseTInv uint16 = 1 << 1 |
| LLDPMAUPMD10BaseT_FDInv uint16 = 1 << 2 |
| LLDPMAUPMD100BaseT4Inv uint16 = 1 << 3 |
| LLDPMAUPMD100BaseTXInv uint16 = 1 << 4 |
| LLDPMAUPMD100BaseTX_FDInv uint16 = 1 << 5 |
| LLDPMAUPMD100BaseT2Inv uint16 = 1 << 6 |
| LLDPMAUPMD100BaseT2_FDInv uint16 = 1 << 7 |
| LLDPMAUPMDFDXPAUSEInv uint16 = 1 << 8 |
| LLDPMAUPMDFDXAPAUSEInv uint16 = 1 << 9 |
| LLDPMAUPMDFDXSPAUSEInv uint16 = 1 << 10 |
| LLDPMAUPMDFDXBPAUSEInv uint16 = 1 << 11 |
| LLDPMAUPMD1000BaseXInv uint16 = 1 << 12 |
| LLDPMAUPMD1000BaseX_FDInv uint16 = 1 << 13 |
| LLDPMAUPMD1000BaseTInv uint16 = 1 << 14 |
| LLDPMAUPMD1000BaseT_FDInv uint16 = 1 << 15 |
| ) |
| |
| type LLDPMACPHYConfigStatus struct { |
| AutoNegSupported bool |
| AutoNegEnabled bool |
| AutoNegCapability uint16 |
| MAUType uint16 |
| } |
| |
| // MDI Power options |
| const ( |
| LLDPMDIPowerPortClass byte = 1 << 0 |
| LLDPMDIPowerCapability byte = 1 << 1 |
| LLDPMDIPowerStatus byte = 1 << 2 |
| LLDPMDIPowerPairsAbility byte = 1 << 3 |
| ) |
| |
| type LLDPPowerType byte |
| |
| type LLDPPowerSource byte |
| |
| type LLDPPowerPriority byte |
| |
| const ( |
| LLDPPowerPriorityUnknown LLDPPowerPriority = 0 |
| LLDPPowerPriorityMedium LLDPPowerPriority = 1 |
| LLDPPowerPriorityHigh LLDPPowerPriority = 2 |
| LLDPPowerPriorityLow LLDPPowerPriority = 3 |
| ) |
| |
| type LLDPPowerViaMDI8023 struct { |
| PortClassPSE bool // false = PD |
| PSESupported bool |
| PSEEnabled bool |
| PSEPairsAbility bool |
| PSEPowerPair uint8 |
| PSEClass uint8 |
| Type LLDPPowerType |
| Source LLDPPowerSource |
| Priority LLDPPowerPriority |
| Requested uint16 // 1-510 Watts |
| Allocated uint16 // 1-510 Watts |
| } |
| |
| // LLDPInfo8023 represents the information carried in 802.3 Org-specific TLVs |
| type LLDPInfo8023 struct { |
| MACPHYConfigStatus LLDPMACPHYConfigStatus |
| PowerViaMDI LLDPPowerViaMDI8023 |
| LinkAggregation LLDPLinkAggregation |
| MTU uint16 |
| } |
| |
| // IEEE 802.1Qbg TLV Subtypes |
| const ( |
| LLDP8021QbgEVB uint8 = 0 |
| LLDP8021QbgCDCP uint8 = 1 |
| LLDP8021QbgVDP uint8 = 2 |
| LLDP8021QbgEVB22 uint8 = 13 |
| ) |
| |
| // LLDPEVBCapabilities Types |
| const ( |
| LLDPEVBCapsSTD uint16 = 1 << 7 |
| LLDPEVBCapsRR uint16 = 1 << 6 |
| LLDPEVBCapsRTE uint16 = 1 << 2 |
| LLDPEVBCapsECP uint16 = 1 << 1 |
| LLDPEVBCapsVDP uint16 = 1 << 0 |
| ) |
| |
| // LLDPEVBCapabilities represents the EVB capabilities of a device |
| type LLDPEVBCapabilities struct { |
| StandardBridging bool |
| ReflectiveRelay bool |
| RetransmissionTimerExponent bool |
| EdgeControlProtocol bool |
| VSIDiscoveryProtocol bool |
| } |
| |
| type LLDPEVBSettings struct { |
| Supported LLDPEVBCapabilities |
| Enabled LLDPEVBCapabilities |
| SupportedVSIs uint16 |
| ConfiguredVSIs uint16 |
| RTEExponent uint8 |
| } |
| |
| // LLDPInfo8021Qbg represents the information carried in 802.1Qbg Org-specific TLVs |
| type LLDPInfo8021Qbg struct { |
| EVBSettings LLDPEVBSettings |
| } |
| |
| type LLDPMediaSubtype uint8 |
| |
| // Media TLV Subtypes |
| const ( |
| LLDPMediaTypeCapabilities LLDPMediaSubtype = 1 |
| LLDPMediaTypeNetwork LLDPMediaSubtype = 2 |
| LLDPMediaTypeLocation LLDPMediaSubtype = 3 |
| LLDPMediaTypePower LLDPMediaSubtype = 4 |
| LLDPMediaTypeHardware LLDPMediaSubtype = 5 |
| LLDPMediaTypeFirmware LLDPMediaSubtype = 6 |
| LLDPMediaTypeSoftware LLDPMediaSubtype = 7 |
| LLDPMediaTypeSerial LLDPMediaSubtype = 8 |
| LLDPMediaTypeManufacturer LLDPMediaSubtype = 9 |
| LLDPMediaTypeModel LLDPMediaSubtype = 10 |
| LLDPMediaTypeAssetID LLDPMediaSubtype = 11 |
| ) |
| |
| type LLDPMediaClass uint8 |
| |
| // Media Class Values |
| const ( |
| LLDPMediaClassUndefined LLDPMediaClass = 0 |
| LLDPMediaClassEndpointI LLDPMediaClass = 1 |
| LLDPMediaClassEndpointII LLDPMediaClass = 2 |
| LLDPMediaClassEndpointIII LLDPMediaClass = 3 |
| LLDPMediaClassNetwork LLDPMediaClass = 4 |
| ) |
| |
| // LLDPMediaCapabilities Types |
| const ( |
| LLDPMediaCapsLLDP uint16 = 1 << 0 |
| LLDPMediaCapsNetwork uint16 = 1 << 1 |
| LLDPMediaCapsLocation uint16 = 1 << 2 |
| LLDPMediaCapsPowerPSE uint16 = 1 << 3 |
| LLDPMediaCapsPowerPD uint16 = 1 << 4 |
| LLDPMediaCapsInventory uint16 = 1 << 5 |
| ) |
| |
| // LLDPMediaCapabilities represents the LLDP Media capabilities of a device |
| type LLDPMediaCapabilities struct { |
| Capabilities bool |
| NetworkPolicy bool |
| Location bool |
| PowerPSE bool |
| PowerPD bool |
| Inventory bool |
| Class LLDPMediaClass |
| } |
| |
| type LLDPApplicationType uint8 |
| |
| const ( |
| LLDPAppTypeReserved LLDPApplicationType = 0 |
| LLDPAppTypeVoice LLDPApplicationType = 1 |
| LLDPappTypeVoiceSignaling LLDPApplicationType = 2 |
| LLDPappTypeGuestVoice LLDPApplicationType = 3 |
| LLDPappTypeGuestVoiceSignaling LLDPApplicationType = 4 |
| LLDPappTypeSoftphoneVoice LLDPApplicationType = 5 |
| LLDPappTypeVideoConferencing LLDPApplicationType = 6 |
| LLDPappTypeStreamingVideo LLDPApplicationType = 7 |
| LLDPappTypeVideoSignaling LLDPApplicationType = 8 |
| ) |
| |
| type LLDPNetworkPolicy struct { |
| ApplicationType LLDPApplicationType |
| Defined bool |
| Tagged bool |
| VLANId uint16 |
| L2Priority uint16 |
| DSCPValue uint8 |
| } |
| |
| type LLDPLocationFormat uint8 |
| |
| const ( |
| LLDPLocationFormatInvalid LLDPLocationFormat = 0 |
| LLDPLocationFormatCoordinate LLDPLocationFormat = 1 |
| LLDPLocationFormatAddress LLDPLocationFormat = 2 |
| LLDPLocationFormatECS LLDPLocationFormat = 3 |
| ) |
| |
| type LLDPLocationAddressWhat uint8 |
| |
| const ( |
| LLDPLocationAddressWhatDHCP LLDPLocationAddressWhat = 0 |
| LLDPLocationAddressWhatNetwork LLDPLocationAddressWhat = 1 |
| LLDPLocationAddressWhatClient LLDPLocationAddressWhat = 2 |
| ) |
| |
| type LLDPLocationAddressType uint8 |
| |
| const ( |
| LLDPLocationAddressTypeLanguage LLDPLocationAddressType = 0 |
| LLDPLocationAddressTypeNational LLDPLocationAddressType = 1 |
| LLDPLocationAddressTypeCounty LLDPLocationAddressType = 2 |
| LLDPLocationAddressTypeCity LLDPLocationAddressType = 3 |
| LLDPLocationAddressTypeCityDivision LLDPLocationAddressType = 4 |
| LLDPLocationAddressTypeNeighborhood LLDPLocationAddressType = 5 |
| LLDPLocationAddressTypeStreet LLDPLocationAddressType = 6 |
| LLDPLocationAddressTypeLeadingStreet LLDPLocationAddressType = 16 |
| LLDPLocationAddressTypeTrailingStreet LLDPLocationAddressType = 17 |
| LLDPLocationAddressTypeStreetSuffix LLDPLocationAddressType = 18 |
| LLDPLocationAddressTypeHouseNum LLDPLocationAddressType = 19 |
| LLDPLocationAddressTypeHouseSuffix LLDPLocationAddressType = 20 |
| LLDPLocationAddressTypeLandmark LLDPLocationAddressType = 21 |
| LLDPLocationAddressTypeAdditional LLDPLocationAddressType = 22 |
| LLDPLocationAddressTypeName LLDPLocationAddressType = 23 |
| LLDPLocationAddressTypePostal LLDPLocationAddressType = 24 |
| LLDPLocationAddressTypeBuilding LLDPLocationAddressType = 25 |
| LLDPLocationAddressTypeUnit LLDPLocationAddressType = 26 |
| LLDPLocationAddressTypeFloor LLDPLocationAddressType = 27 |
| LLDPLocationAddressTypeRoom LLDPLocationAddressType = 28 |
| LLDPLocationAddressTypePlace LLDPLocationAddressType = 29 |
| LLDPLocationAddressTypeScript LLDPLocationAddressType = 128 |
| ) |
| |
| type LLDPLocationCoordinate struct { |
| LatitudeResolution uint8 |
| Latitude uint64 |
| LongitudeResolution uint8 |
| Longitude uint64 |
| AltitudeType uint8 |
| AltitudeResolution uint16 |
| Altitude uint32 |
| Datum uint8 |
| } |
| |
| type LLDPLocationAddressLine struct { |
| Type LLDPLocationAddressType |
| Value string |
| } |
| |
| type LLDPLocationAddress struct { |
| What LLDPLocationAddressWhat |
| CountryCode string |
| AddressLines []LLDPLocationAddressLine |
| } |
| |
| type LLDPLocationECS struct { |
| ELIN string |
| } |
| |
| // LLDP represents a physical location. |
| // Only one of the embedded types will contain values, depending on Format. |
| type LLDPLocation struct { |
| Format LLDPLocationFormat |
| Coordinate LLDPLocationCoordinate |
| Address LLDPLocationAddress |
| ECS LLDPLocationECS |
| } |
| |
| type LLDPPowerViaMDI struct { |
| Type LLDPPowerType |
| Source LLDPPowerSource |
| Priority LLDPPowerPriority |
| Value uint16 |
| } |
| |
| // LLDPInfoMedia represents the information carried in TR-41 Org-specific TLVs |
| type LLDPInfoMedia struct { |
| MediaCapabilities LLDPMediaCapabilities |
| NetworkPolicy LLDPNetworkPolicy |
| Location LLDPLocation |
| PowerViaMDI LLDPPowerViaMDI |
| HardwareRevision string |
| FirmwareRevision string |
| SoftwareRevision string |
| SerialNumber string |
| Manufacturer string |
| Model string |
| AssetID string |
| } |
| |
| type LLDPCisco2Subtype uint8 |
| |
| // Cisco2 TLV Subtypes |
| const ( |
| LLDPCisco2PowerViaMDI LLDPCisco2Subtype = 1 |
| ) |
| |
| const ( |
| LLDPCiscoPSESupport uint8 = 1 << 0 |
| LLDPCiscoArchShared uint8 = 1 << 1 |
| LLDPCiscoPDSparePair uint8 = 1 << 2 |
| LLDPCiscoPSESparePair uint8 = 1 << 3 |
| ) |
| |
| // LLDPInfoCisco2 represents the information carried in Cisco Org-specific TLVs |
| type LLDPInfoCisco2 struct { |
| PSEFourWirePoESupported bool |
| PDSparePairArchitectureShared bool |
| PDRequestSparePairPoEOn bool |
| PSESparePairPoEOn bool |
| } |
| |
| // Profinet Subtypes |
| type LLDPProfinetSubtype uint8 |
| |
| const ( |
| LLDPProfinetPNIODelay LLDPProfinetSubtype = 1 |
| LLDPProfinetPNIOPortStatus LLDPProfinetSubtype = 2 |
| LLDPProfinetPNIOMRPPortStatus LLDPProfinetSubtype = 4 |
| LLDPProfinetPNIOChassisMAC LLDPProfinetSubtype = 5 |
| LLDPProfinetPNIOPTCPStatus LLDPProfinetSubtype = 6 |
| ) |
| |
| type LLDPPNIODelay struct { |
| RXLocal uint32 |
| RXRemote uint32 |
| TXLocal uint32 |
| TXRemote uint32 |
| CableLocal uint32 |
| } |
| |
| type LLDPPNIOPortStatus struct { |
| Class2 uint16 |
| Class3 uint16 |
| } |
| |
| type LLDPPNIOMRPPortStatus struct { |
| UUID []byte |
| Status uint16 |
| } |
| |
| type LLDPPNIOPTCPStatus struct { |
| MasterAddress []byte |
| SubdomainUUID []byte |
| IRDataUUID []byte |
| PeriodValid bool |
| PeriodLength uint32 |
| RedPeriodValid bool |
| RedPeriodBegin uint32 |
| OrangePeriodValid bool |
| OrangePeriodBegin uint32 |
| GreenPeriodValid bool |
| GreenPeriodBegin uint32 |
| } |
| |
| // LLDPInfoProfinet represents the information carried in Profinet Org-specific TLVs |
| type LLDPInfoProfinet struct { |
| PNIODelay LLDPPNIODelay |
| PNIOPortStatus LLDPPNIOPortStatus |
| PNIOMRPPortStatus LLDPPNIOMRPPortStatus |
| ChassisMAC []byte |
| PNIOPTCPStatus LLDPPNIOPTCPStatus |
| } |
| |
| // LayerType returns gopacket.LayerTypeLinkLayerDiscovery. |
| func (c *LinkLayerDiscovery) LayerType() gopacket.LayerType { |
| return LayerTypeLinkLayerDiscovery |
| } |
| |
| // SerializeTo serializes LLDP packet to bytes and writes on SerializeBuffer. |
| func (c *LinkLayerDiscovery) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { |
| chassIDLen := c.ChassisID.serializedLen() |
| portIDLen := c.PortID.serializedLen() |
| vb, err := b.AppendBytes(chassIDLen + portIDLen + 4) // +4 for TTL |
| if err != nil { |
| return err |
| } |
| copy(vb[:chassIDLen], c.ChassisID.serialize()) |
| copy(vb[chassIDLen:], c.PortID.serialize()) |
| ttlIDLen := uint16(LLDPTLVTTL)<<9 | uint16(2) |
| binary.BigEndian.PutUint16(vb[chassIDLen+portIDLen:], ttlIDLen) |
| binary.BigEndian.PutUint16(vb[chassIDLen+portIDLen+2:], c.TTL) |
| |
| vb, err = b.AppendBytes(2) // End Tlv, 2 bytes |
| if err != nil { |
| return err |
| } |
| binary.BigEndian.PutUint16(vb[len(vb)-2:], uint16(0)) //End tlv, 2 bytes, all zero |
| return nil |
| |
| } |
| |
| func decodeLinkLayerDiscovery(data []byte, p gopacket.PacketBuilder) error { |
| var vals []LinkLayerDiscoveryValue |
| vData := data[0:] |
| for len(vData) > 0 { |
| nbit := vData[0] & 0x01 |
| t := LLDPTLVType(vData[0] >> 1) |
| val := LinkLayerDiscoveryValue{Type: t, Length: uint16(nbit)<<8 + uint16(vData[1])} |
| if val.Length > 0 { |
| val.Value = vData[2 : val.Length+2] |
| } |
| vals = append(vals, val) |
| if t == LLDPTLVEnd { |
| break |
| } |
| if len(vData) < int(2+val.Length) { |
| return errors.New("Malformed LinkLayerDiscovery Header") |
| } |
| vData = vData[2+val.Length:] |
| } |
| if len(vals) < 4 { |
| return errors.New("Missing mandatory LinkLayerDiscovery TLV") |
| } |
| c := &LinkLayerDiscovery{} |
| gotEnd := false |
| for _, v := range vals { |
| switch v.Type { |
| case LLDPTLVEnd: |
| gotEnd = true |
| case LLDPTLVChassisID: |
| if len(v.Value) < 2 { |
| return errors.New("Malformed LinkLayerDiscovery ChassisID TLV") |
| } |
| c.ChassisID.Subtype = LLDPChassisIDSubType(v.Value[0]) |
| c.ChassisID.ID = v.Value[1:] |
| case LLDPTLVPortID: |
| if len(v.Value) < 2 { |
| return errors.New("Malformed LinkLayerDiscovery PortID TLV") |
| } |
| c.PortID.Subtype = LLDPPortIDSubType(v.Value[0]) |
| c.PortID.ID = v.Value[1:] |
| case LLDPTLVTTL: |
| if len(v.Value) < 2 { |
| return errors.New("Malformed LinkLayerDiscovery TTL TLV") |
| } |
| c.TTL = binary.BigEndian.Uint16(v.Value[0:2]) |
| default: |
| c.Values = append(c.Values, v) |
| } |
| } |
| if c.ChassisID.Subtype == 0 || c.PortID.Subtype == 0 || !gotEnd { |
| return errors.New("Missing mandatory LinkLayerDiscovery TLV") |
| } |
| c.Contents = data |
| p.AddLayer(c) |
| |
| info := &LinkLayerDiscoveryInfo{} |
| p.AddLayer(info) |
| for _, v := range c.Values { |
| switch v.Type { |
| case LLDPTLVPortDescription: |
| info.PortDescription = string(v.Value) |
| case LLDPTLVSysName: |
| info.SysName = string(v.Value) |
| case LLDPTLVSysDescription: |
| info.SysDescription = string(v.Value) |
| case LLDPTLVSysCapabilities: |
| if err := checkLLDPTLVLen(v, 4); err != nil { |
| return err |
| } |
| info.SysCapabilities.SystemCap = getCapabilities(binary.BigEndian.Uint16(v.Value[0:2])) |
| info.SysCapabilities.EnabledCap = getCapabilities(binary.BigEndian.Uint16(v.Value[2:4])) |
| case LLDPTLVMgmtAddress: |
| if err := checkLLDPTLVLen(v, 9); err != nil { |
| return err |
| } |
| mlen := v.Value[0] |
| if err := checkLLDPTLVLen(v, int(mlen+7)); err != nil { |
| return err |
| } |
| info.MgmtAddress.Subtype = IANAAddressFamily(v.Value[1]) |
| info.MgmtAddress.Address = v.Value[2 : mlen+1] |
| info.MgmtAddress.InterfaceSubtype = LLDPInterfaceSubtype(v.Value[mlen+1]) |
| info.MgmtAddress.InterfaceNumber = binary.BigEndian.Uint32(v.Value[mlen+2 : mlen+6]) |
| olen := v.Value[mlen+6] |
| if err := checkLLDPTLVLen(v, int(mlen+6+olen)); err != nil { |
| return err |
| } |
| info.MgmtAddress.OID = string(v.Value[mlen+9 : mlen+9+olen]) |
| case LLDPTLVOrgSpecific: |
| if err := checkLLDPTLVLen(v, 4); err != nil { |
| return err |
| } |
| info.OrgTLVs = append(info.OrgTLVs, LLDPOrgSpecificTLV{IEEEOUI(binary.BigEndian.Uint32(append([]byte{byte(0)}, v.Value[0:3]...))), uint8(v.Value[3]), v.Value[4:]}) |
| } |
| } |
| return nil |
| } |
| |
| func (l *LinkLayerDiscoveryInfo) Decode8021() (info LLDPInfo8021, err error) { |
| for _, o := range l.OrgTLVs { |
| if o.OUI != IEEEOUI8021 { |
| continue |
| } |
| switch o.SubType { |
| case LLDP8021SubtypePortVLANID: |
| if err = checkLLDPOrgSpecificLen(o, 2); err != nil { |
| return |
| } |
| info.PVID = binary.BigEndian.Uint16(o.Info[0:2]) |
| case LLDP8021SubtypeProtocolVLANID: |
| if err = checkLLDPOrgSpecificLen(o, 3); err != nil { |
| return |
| } |
| sup := (o.Info[0]&LLDPProtocolVLANIDCapability > 0) |
| en := (o.Info[0]&LLDPProtocolVLANIDStatus > 0) |
| id := binary.BigEndian.Uint16(o.Info[1:3]) |
| info.PPVIDs = append(info.PPVIDs, PortProtocolVLANID{sup, en, id}) |
| case LLDP8021SubtypeVLANName: |
| if err = checkLLDPOrgSpecificLen(o, 2); err != nil { |
| return |
| } |
| id := binary.BigEndian.Uint16(o.Info[0:2]) |
| info.VLANNames = append(info.VLANNames, VLANName{id, string(o.Info[3:])}) |
| case LLDP8021SubtypeProtocolIdentity: |
| if err = checkLLDPOrgSpecificLen(o, 1); err != nil { |
| return |
| } |
| l := int(o.Info[0]) |
| if l > 0 { |
| info.ProtocolIdentities = append(info.ProtocolIdentities, o.Info[1:1+l]) |
| } |
| case LLDP8021SubtypeVDIUsageDigest: |
| if err = checkLLDPOrgSpecificLen(o, 4); err != nil { |
| return |
| } |
| info.VIDUsageDigest = binary.BigEndian.Uint32(o.Info[0:4]) |
| case LLDP8021SubtypeManagementVID: |
| if err = checkLLDPOrgSpecificLen(o, 2); err != nil { |
| return |
| } |
| info.ManagementVID = binary.BigEndian.Uint16(o.Info[0:2]) |
| case LLDP8021SubtypeLinkAggregation: |
| if err = checkLLDPOrgSpecificLen(o, 5); err != nil { |
| return |
| } |
| sup := (o.Info[0]&LLDPAggregationCapability > 0) |
| en := (o.Info[0]&LLDPAggregationStatus > 0) |
| info.LinkAggregation = LLDPLinkAggregation{sup, en, binary.BigEndian.Uint32(o.Info[1:5])} |
| } |
| } |
| return |
| } |
| |
| func (l *LinkLayerDiscoveryInfo) Decode8023() (info LLDPInfo8023, err error) { |
| for _, o := range l.OrgTLVs { |
| if o.OUI != IEEEOUI8023 { |
| continue |
| } |
| switch o.SubType { |
| case LLDP8023SubtypeMACPHY: |
| if err = checkLLDPOrgSpecificLen(o, 5); err != nil { |
| return |
| } |
| sup := (o.Info[0]&LLDPMACPHYCapability > 0) |
| en := (o.Info[0]&LLDPMACPHYStatus > 0) |
| ca := binary.BigEndian.Uint16(o.Info[1:3]) |
| mau := binary.BigEndian.Uint16(o.Info[3:5]) |
| info.MACPHYConfigStatus = LLDPMACPHYConfigStatus{sup, en, ca, mau} |
| case LLDP8023SubtypeMDIPower: |
| if err = checkLLDPOrgSpecificLen(o, 3); err != nil { |
| return |
| } |
| info.PowerViaMDI.PortClassPSE = (o.Info[0]&LLDPMDIPowerPortClass > 0) |
| info.PowerViaMDI.PSESupported = (o.Info[0]&LLDPMDIPowerCapability > 0) |
| info.PowerViaMDI.PSEEnabled = (o.Info[0]&LLDPMDIPowerStatus > 0) |
| info.PowerViaMDI.PSEPairsAbility = (o.Info[0]&LLDPMDIPowerPairsAbility > 0) |
| info.PowerViaMDI.PSEPowerPair = uint8(o.Info[1]) |
| info.PowerViaMDI.PSEClass = uint8(o.Info[2]) |
| if len(o.Info) >= 7 { |
| info.PowerViaMDI.Type = LLDPPowerType((o.Info[3] & 0xc0) >> 6) |
| info.PowerViaMDI.Source = LLDPPowerSource((o.Info[3] & 0x30) >> 4) |
| if info.PowerViaMDI.Type == 1 || info.PowerViaMDI.Type == 3 { |
| info.PowerViaMDI.Source += 128 // For Stringify purposes |
| } |
| info.PowerViaMDI.Priority = LLDPPowerPriority(o.Info[3] & 0x0f) |
| info.PowerViaMDI.Requested = binary.BigEndian.Uint16(o.Info[4:6]) |
| info.PowerViaMDI.Allocated = binary.BigEndian.Uint16(o.Info[6:8]) |
| } |
| case LLDP8023SubtypeLinkAggregation: |
| if err = checkLLDPOrgSpecificLen(o, 5); err != nil { |
| return |
| } |
| sup := (o.Info[0]&LLDPAggregationCapability > 0) |
| en := (o.Info[0]&LLDPAggregationStatus > 0) |
| info.LinkAggregation = LLDPLinkAggregation{sup, en, binary.BigEndian.Uint32(o.Info[1:5])} |
| case LLDP8023SubtypeMTU: |
| if err = checkLLDPOrgSpecificLen(o, 2); err != nil { |
| return |
| } |
| info.MTU = binary.BigEndian.Uint16(o.Info[0:2]) |
| } |
| } |
| return |
| } |
| |
| func (l *LinkLayerDiscoveryInfo) Decode8021Qbg() (info LLDPInfo8021Qbg, err error) { |
| for _, o := range l.OrgTLVs { |
| if o.OUI != IEEEOUI8021Qbg { |
| continue |
| } |
| switch o.SubType { |
| case LLDP8021QbgEVB: |
| if err = checkLLDPOrgSpecificLen(o, 9); err != nil { |
| return |
| } |
| info.EVBSettings.Supported = getEVBCapabilities(binary.BigEndian.Uint16(o.Info[0:2])) |
| info.EVBSettings.Enabled = getEVBCapabilities(binary.BigEndian.Uint16(o.Info[2:4])) |
| info.EVBSettings.SupportedVSIs = binary.BigEndian.Uint16(o.Info[4:6]) |
| info.EVBSettings.ConfiguredVSIs = binary.BigEndian.Uint16(o.Info[6:8]) |
| info.EVBSettings.RTEExponent = uint8(o.Info[8]) |
| } |
| } |
| return |
| } |
| |
| func (l *LinkLayerDiscoveryInfo) DecodeMedia() (info LLDPInfoMedia, err error) { |
| for _, o := range l.OrgTLVs { |
| if o.OUI != IEEEOUIMedia { |
| continue |
| } |
| switch LLDPMediaSubtype(o.SubType) { |
| case LLDPMediaTypeCapabilities: |
| if err = checkLLDPOrgSpecificLen(o, 3); err != nil { |
| return |
| } |
| b := binary.BigEndian.Uint16(o.Info[0:2]) |
| info.MediaCapabilities.Capabilities = (b & LLDPMediaCapsLLDP) > 0 |
| info.MediaCapabilities.NetworkPolicy = (b & LLDPMediaCapsNetwork) > 0 |
| info.MediaCapabilities.Location = (b & LLDPMediaCapsLocation) > 0 |
| info.MediaCapabilities.PowerPSE = (b & LLDPMediaCapsPowerPSE) > 0 |
| info.MediaCapabilities.PowerPD = (b & LLDPMediaCapsPowerPD) > 0 |
| info.MediaCapabilities.Inventory = (b & LLDPMediaCapsInventory) > 0 |
| info.MediaCapabilities.Class = LLDPMediaClass(o.Info[2]) |
| case LLDPMediaTypeNetwork: |
| if err = checkLLDPOrgSpecificLen(o, 4); err != nil { |
| return |
| } |
| info.NetworkPolicy.ApplicationType = LLDPApplicationType(o.Info[0]) |
| b := binary.BigEndian.Uint16(o.Info[1:3]) |
| info.NetworkPolicy.Defined = (b & 0x8000) == 0 |
| info.NetworkPolicy.Tagged = (b & 0x4000) > 0 |
| info.NetworkPolicy.VLANId = (b & 0x1ffe) >> 1 |
| b = binary.BigEndian.Uint16(o.Info[2:4]) |
| info.NetworkPolicy.L2Priority = (b & 0x01c0) >> 6 |
| info.NetworkPolicy.DSCPValue = uint8(o.Info[3] & 0x3f) |
| case LLDPMediaTypeLocation: |
| if err = checkLLDPOrgSpecificLen(o, 1); err != nil { |
| return |
| } |
| info.Location.Format = LLDPLocationFormat(o.Info[0]) |
| o.Info = o.Info[1:] |
| switch info.Location.Format { |
| case LLDPLocationFormatCoordinate: |
| if err = checkLLDPOrgSpecificLen(o, 16); err != nil { |
| return |
| } |
| info.Location.Coordinate.LatitudeResolution = uint8(o.Info[0]&0xfc) >> 2 |
| b := binary.BigEndian.Uint64(o.Info[0:8]) |
| info.Location.Coordinate.Latitude = (b & 0x03ffffffff000000) >> 24 |
| info.Location.Coordinate.LongitudeResolution = uint8(o.Info[5]&0xfc) >> 2 |
| b = binary.BigEndian.Uint64(o.Info[5:13]) |
| info.Location.Coordinate.Longitude = (b & 0x03ffffffff000000) >> 24 |
| info.Location.Coordinate.AltitudeType = uint8((o.Info[10] & 0x30) >> 4) |
| b1 := binary.BigEndian.Uint16(o.Info[10:12]) |
| info.Location.Coordinate.AltitudeResolution = (b1 & 0xfc0) >> 6 |
| b2 := binary.BigEndian.Uint32(o.Info[11:15]) |
| info.Location.Coordinate.Altitude = b2 & 0x3fffffff |
| info.Location.Coordinate.Datum = uint8(o.Info[15]) |
| case LLDPLocationFormatAddress: |
| if err = checkLLDPOrgSpecificLen(o, 3); err != nil { |
| return |
| } |
| //ll := uint8(o.Info[0]) |
| info.Location.Address.What = LLDPLocationAddressWhat(o.Info[1]) |
| info.Location.Address.CountryCode = string(o.Info[2:4]) |
| data := o.Info[4:] |
| for len(data) > 1 { |
| aType := LLDPLocationAddressType(data[0]) |
| aLen := int(data[1]) |
| if len(data) >= aLen+2 { |
| info.Location.Address.AddressLines = append(info.Location.Address.AddressLines, LLDPLocationAddressLine{aType, string(data[2 : aLen+2])}) |
| data = data[aLen+2:] |
| } else { |
| break |
| } |
| } |
| case LLDPLocationFormatECS: |
| info.Location.ECS.ELIN = string(o.Info) |
| } |
| case LLDPMediaTypePower: |
| if err = checkLLDPOrgSpecificLen(o, 3); err != nil { |
| return |
| } |
| info.PowerViaMDI.Type = LLDPPowerType((o.Info[0] & 0xc0) >> 6) |
| info.PowerViaMDI.Source = LLDPPowerSource((o.Info[0] & 0x30) >> 4) |
| if info.PowerViaMDI.Type == 1 || info.PowerViaMDI.Type == 3 { |
| info.PowerViaMDI.Source += 128 // For Stringify purposes |
| } |
| info.PowerViaMDI.Priority = LLDPPowerPriority(o.Info[0] & 0x0f) |
| info.PowerViaMDI.Value = binary.BigEndian.Uint16(o.Info[1:3]) * 100 // 0 to 102.3 w, 0.1W increments |
| case LLDPMediaTypeHardware: |
| info.HardwareRevision = string(o.Info) |
| case LLDPMediaTypeFirmware: |
| info.FirmwareRevision = string(o.Info) |
| case LLDPMediaTypeSoftware: |
| info.SoftwareRevision = string(o.Info) |
| case LLDPMediaTypeSerial: |
| info.SerialNumber = string(o.Info) |
| case LLDPMediaTypeManufacturer: |
| info.Manufacturer = string(o.Info) |
| case LLDPMediaTypeModel: |
| info.Model = string(o.Info) |
| case LLDPMediaTypeAssetID: |
| info.AssetID = string(o.Info) |
| } |
| } |
| return |
| } |
| |
| func (l *LinkLayerDiscoveryInfo) DecodeCisco2() (info LLDPInfoCisco2, err error) { |
| for _, o := range l.OrgTLVs { |
| if o.OUI != IEEEOUICisco2 { |
| continue |
| } |
| switch LLDPCisco2Subtype(o.SubType) { |
| case LLDPCisco2PowerViaMDI: |
| if err = checkLLDPOrgSpecificLen(o, 1); err != nil { |
| return |
| } |
| info.PSEFourWirePoESupported = (o.Info[0] & LLDPCiscoPSESupport) > 0 |
| info.PDSparePairArchitectureShared = (o.Info[0] & LLDPCiscoArchShared) > 0 |
| info.PDRequestSparePairPoEOn = (o.Info[0] & LLDPCiscoPDSparePair) > 0 |
| info.PSESparePairPoEOn = (o.Info[0] & LLDPCiscoPSESparePair) > 0 |
| } |
| } |
| return |
| } |
| |
| func (l *LinkLayerDiscoveryInfo) DecodeProfinet() (info LLDPInfoProfinet, err error) { |
| for _, o := range l.OrgTLVs { |
| if o.OUI != IEEEOUIProfinet { |
| continue |
| } |
| switch LLDPProfinetSubtype(o.SubType) { |
| case LLDPProfinetPNIODelay: |
| if err = checkLLDPOrgSpecificLen(o, 20); err != nil { |
| return |
| } |
| info.PNIODelay.RXLocal = binary.BigEndian.Uint32(o.Info[0:4]) |
| info.PNIODelay.RXRemote = binary.BigEndian.Uint32(o.Info[4:8]) |
| info.PNIODelay.TXLocal = binary.BigEndian.Uint32(o.Info[8:12]) |
| info.PNIODelay.TXRemote = binary.BigEndian.Uint32(o.Info[12:16]) |
| info.PNIODelay.CableLocal = binary.BigEndian.Uint32(o.Info[16:20]) |
| case LLDPProfinetPNIOPortStatus: |
| if err = checkLLDPOrgSpecificLen(o, 4); err != nil { |
| return |
| } |
| info.PNIOPortStatus.Class2 = binary.BigEndian.Uint16(o.Info[0:2]) |
| info.PNIOPortStatus.Class3 = binary.BigEndian.Uint16(o.Info[2:4]) |
| case LLDPProfinetPNIOMRPPortStatus: |
| if err = checkLLDPOrgSpecificLen(o, 18); err != nil { |
| return |
| } |
| info.PNIOMRPPortStatus.UUID = o.Info[0:16] |
| info.PNIOMRPPortStatus.Status = binary.BigEndian.Uint16(o.Info[16:18]) |
| case LLDPProfinetPNIOChassisMAC: |
| if err = checkLLDPOrgSpecificLen(o, 6); err != nil { |
| return |
| } |
| info.ChassisMAC = o.Info[0:6] |
| case LLDPProfinetPNIOPTCPStatus: |
| if err = checkLLDPOrgSpecificLen(o, 54); err != nil { |
| return |
| } |
| info.PNIOPTCPStatus.MasterAddress = o.Info[0:6] |
| info.PNIOPTCPStatus.SubdomainUUID = o.Info[6:22] |
| info.PNIOPTCPStatus.IRDataUUID = o.Info[22:38] |
| b := binary.BigEndian.Uint32(o.Info[38:42]) |
| info.PNIOPTCPStatus.PeriodValid = (b & 0x80000000) > 0 |
| info.PNIOPTCPStatus.PeriodLength = b & 0x7fffffff |
| b = binary.BigEndian.Uint32(o.Info[42:46]) |
| info.PNIOPTCPStatus.RedPeriodValid = (b & 0x80000000) > 0 |
| info.PNIOPTCPStatus.RedPeriodBegin = b & 0x7fffffff |
| b = binary.BigEndian.Uint32(o.Info[46:50]) |
| info.PNIOPTCPStatus.OrangePeriodValid = (b & 0x80000000) > 0 |
| info.PNIOPTCPStatus.OrangePeriodBegin = b & 0x7fffffff |
| b = binary.BigEndian.Uint32(o.Info[50:54]) |
| info.PNIOPTCPStatus.GreenPeriodValid = (b & 0x80000000) > 0 |
| info.PNIOPTCPStatus.GreenPeriodBegin = b & 0x7fffffff |
| } |
| } |
| return |
| } |
| |
| // LayerType returns gopacket.LayerTypeLinkLayerDiscoveryInfo. |
| func (c *LinkLayerDiscoveryInfo) LayerType() gopacket.LayerType { |
| return LayerTypeLinkLayerDiscoveryInfo |
| } |
| |
| func getCapabilities(v uint16) (c LLDPCapabilities) { |
| c.Other = (v&LLDPCapsOther > 0) |
| c.Repeater = (v&LLDPCapsRepeater > 0) |
| c.Bridge = (v&LLDPCapsBridge > 0) |
| c.WLANAP = (v&LLDPCapsWLANAP > 0) |
| c.Router = (v&LLDPCapsRouter > 0) |
| c.Phone = (v&LLDPCapsPhone > 0) |
| c.DocSis = (v&LLDPCapsDocSis > 0) |
| c.StationOnly = (v&LLDPCapsStationOnly > 0) |
| c.CVLAN = (v&LLDPCapsCVLAN > 0) |
| c.SVLAN = (v&LLDPCapsSVLAN > 0) |
| c.TMPR = (v&LLDPCapsTmpr > 0) |
| return |
| } |
| |
| func getEVBCapabilities(v uint16) (c LLDPEVBCapabilities) { |
| c.StandardBridging = (v & LLDPEVBCapsSTD) > 0 |
| c.StandardBridging = (v & LLDPEVBCapsSTD) > 0 |
| c.ReflectiveRelay = (v & LLDPEVBCapsRR) > 0 |
| c.RetransmissionTimerExponent = (v & LLDPEVBCapsRTE) > 0 |
| c.EdgeControlProtocol = (v & LLDPEVBCapsECP) > 0 |
| c.VSIDiscoveryProtocol = (v & LLDPEVBCapsVDP) > 0 |
| return |
| } |
| |
| func (t LLDPTLVType) String() (s string) { |
| switch t { |
| case LLDPTLVEnd: |
| s = "TLV End" |
| case LLDPTLVChassisID: |
| s = "Chassis ID" |
| case LLDPTLVPortID: |
| s = "Port ID" |
| case LLDPTLVTTL: |
| s = "TTL" |
| case LLDPTLVPortDescription: |
| s = "Port Description" |
| case LLDPTLVSysName: |
| s = "System Name" |
| case LLDPTLVSysDescription: |
| s = "System Description" |
| case LLDPTLVSysCapabilities: |
| s = "System Capabilities" |
| case LLDPTLVMgmtAddress: |
| s = "Management Address" |
| case LLDPTLVOrgSpecific: |
| s = "Organisation Specific" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t LLDPChassisIDSubType) String() (s string) { |
| switch t { |
| case LLDPChassisIDSubTypeReserved: |
| s = "Reserved" |
| case LLDPChassisIDSubTypeChassisComp: |
| s = "Chassis Component" |
| case LLDPChassisIDSubtypeIfaceAlias: |
| s = "Interface Alias" |
| case LLDPChassisIDSubTypePortComp: |
| s = "Port Component" |
| case LLDPChassisIDSubTypeMACAddr: |
| s = "MAC Address" |
| case LLDPChassisIDSubTypeNetworkAddr: |
| s = "Network Address" |
| case LLDPChassisIDSubtypeIfaceName: |
| s = "Interface Name" |
| case LLDPChassisIDSubTypeLocal: |
| s = "Local" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t LLDPPortIDSubType) String() (s string) { |
| switch t { |
| case LLDPPortIDSubtypeReserved: |
| s = "Reserved" |
| case LLDPPortIDSubtypeIfaceAlias: |
| s = "Interface Alias" |
| case LLDPPortIDSubtypePortComp: |
| s = "Port Component" |
| case LLDPPortIDSubtypeMACAddr: |
| s = "MAC Address" |
| case LLDPPortIDSubtypeNetworkAddr: |
| s = "Network Address" |
| case LLDPPortIDSubtypeIfaceName: |
| s = "Interface Name" |
| case LLDPPortIDSubtypeAgentCircuitID: |
| s = "Agent Circuit ID" |
| case LLDPPortIDSubtypeLocal: |
| s = "Local" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t IANAAddressFamily) String() (s string) { |
| switch t { |
| case IANAAddressFamilyReserved: |
| s = "Reserved" |
| case IANAAddressFamilyIPV4: |
| s = "IPv4" |
| case IANAAddressFamilyIPV6: |
| s = "IPv6" |
| case IANAAddressFamilyNSAP: |
| s = "NSAP" |
| case IANAAddressFamilyHDLC: |
| s = "HDLC" |
| case IANAAddressFamilyBBN1822: |
| s = "BBN 1822" |
| case IANAAddressFamily802: |
| s = "802 media plus Ethernet 'canonical format'" |
| case IANAAddressFamilyE163: |
| s = "E.163" |
| case IANAAddressFamilyE164: |
| s = "E.164 (SMDS, Frame Relay, ATM)" |
| case IANAAddressFamilyF69: |
| s = "F.69 (Telex)" |
| case IANAAddressFamilyX121: |
| s = "X.121, X.25, Frame Relay" |
| case IANAAddressFamilyIPX: |
| s = "IPX" |
| case IANAAddressFamilyAtalk: |
| s = "Appletalk" |
| case IANAAddressFamilyDecnet: |
| s = "Decnet IV" |
| case IANAAddressFamilyBanyan: |
| s = "Banyan Vines" |
| case IANAAddressFamilyE164NSAP: |
| s = "E.164 with NSAP format subaddress" |
| case IANAAddressFamilyDNS: |
| s = "DNS" |
| case IANAAddressFamilyDistname: |
| s = "Distinguished Name" |
| case IANAAddressFamilyASNumber: |
| s = "AS Number" |
| case IANAAddressFamilyXTPIPV4: |
| s = "XTP over IP version 4" |
| case IANAAddressFamilyXTPIPV6: |
| s = "XTP over IP version 6" |
| case IANAAddressFamilyXTP: |
| s = "XTP native mode XTP" |
| case IANAAddressFamilyFcWWPN: |
| s = "Fibre Channel World-Wide Port Name" |
| case IANAAddressFamilyFcWWNN: |
| s = "Fibre Channel World-Wide Node Name" |
| case IANAAddressFamilyGWID: |
| s = "GWID" |
| case IANAAddressFamilyL2VPN: |
| s = "AFI for Layer 2 VPN" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t LLDPInterfaceSubtype) String() (s string) { |
| switch t { |
| case LLDPInterfaceSubtypeUnknown: |
| s = "Unknown" |
| case LLDPInterfaceSubtypeifIndex: |
| s = "IfIndex" |
| case LLDPInterfaceSubtypeSysPort: |
| s = "System Port Number" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t LLDPPowerType) String() (s string) { |
| switch t { |
| case 0: |
| s = "Type 2 PSE Device" |
| case 1: |
| s = "Type 2 PD Device" |
| case 2: |
| s = "Type 1 PSE Device" |
| case 3: |
| s = "Type 1 PD Device" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t LLDPPowerSource) String() (s string) { |
| switch t { |
| // PD Device |
| case 0: |
| s = "Unknown" |
| case 1: |
| s = "PSE" |
| case 2: |
| s = "Local" |
| case 3: |
| s = "PSE and Local" |
| // PSE Device (Actual value + 128) |
| case 128: |
| s = "Unknown" |
| case 129: |
| s = "Primary Power Source" |
| case 130: |
| s = "Backup Power Source" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t LLDPPowerPriority) String() (s string) { |
| switch t { |
| case 0: |
| s = "Unknown" |
| case 1: |
| s = "Critical" |
| case 2: |
| s = "High" |
| case 3: |
| s = "Low" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t LLDPMediaSubtype) String() (s string) { |
| switch t { |
| case LLDPMediaTypeCapabilities: |
| s = "Media Capabilities " |
| case LLDPMediaTypeNetwork: |
| s = "Network Policy" |
| case LLDPMediaTypeLocation: |
| s = "Location Identification" |
| case LLDPMediaTypePower: |
| s = "Extended Power-via-MDI" |
| case LLDPMediaTypeHardware: |
| s = "Hardware Revision" |
| case LLDPMediaTypeFirmware: |
| s = "Firmware Revision" |
| case LLDPMediaTypeSoftware: |
| s = "Software Revision" |
| case LLDPMediaTypeSerial: |
| s = "Serial Number" |
| case LLDPMediaTypeManufacturer: |
| s = "Manufacturer" |
| case LLDPMediaTypeModel: |
| s = "Model" |
| case LLDPMediaTypeAssetID: |
| s = "Asset ID" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t LLDPMediaClass) String() (s string) { |
| switch t { |
| case LLDPMediaClassUndefined: |
| s = "Undefined" |
| case LLDPMediaClassEndpointI: |
| s = "Endpoint Class I" |
| case LLDPMediaClassEndpointII: |
| s = "Endpoint Class II" |
| case LLDPMediaClassEndpointIII: |
| s = "Endpoint Class III" |
| case LLDPMediaClassNetwork: |
| s = "Network connectivity " |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t LLDPApplicationType) String() (s string) { |
| switch t { |
| case LLDPAppTypeReserved: |
| s = "Reserved" |
| case LLDPAppTypeVoice: |
| s = "Voice" |
| case LLDPappTypeVoiceSignaling: |
| s = "Voice Signaling" |
| case LLDPappTypeGuestVoice: |
| s = "Guest Voice" |
| case LLDPappTypeGuestVoiceSignaling: |
| s = "Guest Voice Signaling" |
| case LLDPappTypeSoftphoneVoice: |
| s = "Softphone Voice" |
| case LLDPappTypeVideoConferencing: |
| s = "Video Conferencing" |
| case LLDPappTypeStreamingVideo: |
| s = "Streaming Video" |
| case LLDPappTypeVideoSignaling: |
| s = "Video Signaling" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t LLDPLocationFormat) String() (s string) { |
| switch t { |
| case LLDPLocationFormatInvalid: |
| s = "Invalid" |
| case LLDPLocationFormatCoordinate: |
| s = "Coordinate-based LCI" |
| case LLDPLocationFormatAddress: |
| s = "Address-based LCO" |
| case LLDPLocationFormatECS: |
| s = "ECS ELIN" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t LLDPLocationAddressType) String() (s string) { |
| switch t { |
| case LLDPLocationAddressTypeLanguage: |
| s = "Language" |
| case LLDPLocationAddressTypeNational: |
| s = "National subdivisions (province, state, etc)" |
| case LLDPLocationAddressTypeCounty: |
| s = "County, parish, district" |
| case LLDPLocationAddressTypeCity: |
| s = "City, township" |
| case LLDPLocationAddressTypeCityDivision: |
| s = "City division, borough, ward" |
| case LLDPLocationAddressTypeNeighborhood: |
| s = "Neighborhood, block" |
| case LLDPLocationAddressTypeStreet: |
| s = "Street" |
| case LLDPLocationAddressTypeLeadingStreet: |
| s = "Leading street direction" |
| case LLDPLocationAddressTypeTrailingStreet: |
| s = "Trailing street suffix" |
| case LLDPLocationAddressTypeStreetSuffix: |
| s = "Street suffix" |
| case LLDPLocationAddressTypeHouseNum: |
| s = "House number" |
| case LLDPLocationAddressTypeHouseSuffix: |
| s = "House number suffix" |
| case LLDPLocationAddressTypeLandmark: |
| s = "Landmark or vanity address" |
| case LLDPLocationAddressTypeAdditional: |
| s = "Additional location information" |
| case LLDPLocationAddressTypeName: |
| s = "Name" |
| case LLDPLocationAddressTypePostal: |
| s = "Postal/ZIP code" |
| case LLDPLocationAddressTypeBuilding: |
| s = "Building" |
| case LLDPLocationAddressTypeUnit: |
| s = "Unit" |
| case LLDPLocationAddressTypeFloor: |
| s = "Floor" |
| case LLDPLocationAddressTypeRoom: |
| s = "Room number" |
| case LLDPLocationAddressTypePlace: |
| s = "Place type" |
| case LLDPLocationAddressTypeScript: |
| s = "Script" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func checkLLDPTLVLen(v LinkLayerDiscoveryValue, l int) (err error) { |
| if len(v.Value) < l { |
| err = fmt.Errorf("Invalid TLV %v length %d (wanted mimimum %v", v.Type, len(v.Value), l) |
| } |
| return |
| } |
| |
| func checkLLDPOrgSpecificLen(o LLDPOrgSpecificTLV, l int) (err error) { |
| if len(o.Info) < l { |
| err = fmt.Errorf("Invalid Org Specific TLV %v length %d (wanted minimum %v)", o.SubType, len(o.Info), l) |
| } |
| return |
| } |