| // 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. |
| |
| // Enum types courtesy of... |
| // http://search.cpan.org/~mchapman/Net-CDP-0.09/lib/Net/CDP.pm |
| // https://code.google.com/p/ladvd/ |
| // http://anonsvn.wireshark.org/viewvc/releases/wireshark-1.8.6/epan/dissectors/packet-cdp.c |
| |
| package layers |
| |
| import ( |
| "encoding/binary" |
| "fmt" |
| "net" |
| |
| "github.com/google/gopacket" |
| ) |
| |
| // CDPTLVType is the type of each TLV value in a CiscoDiscovery packet. |
| type CDPTLVType uint16 |
| |
| // CDPTLVType values. |
| const ( |
| CDPTLVDevID CDPTLVType = 0x0001 |
| CDPTLVAddress CDPTLVType = 0x0002 |
| CDPTLVPortID CDPTLVType = 0x0003 |
| CDPTLVCapabilities CDPTLVType = 0x0004 |
| CDPTLVVersion CDPTLVType = 0x0005 |
| CDPTLVPlatform CDPTLVType = 0x0006 |
| CDPTLVIPPrefix CDPTLVType = 0x0007 |
| CDPTLVHello CDPTLVType = 0x0008 |
| CDPTLVVTPDomain CDPTLVType = 0x0009 |
| CDPTLVNativeVLAN CDPTLVType = 0x000a |
| CDPTLVFullDuplex CDPTLVType = 0x000b |
| CDPTLVVLANReply CDPTLVType = 0x000e |
| CDPTLVVLANQuery CDPTLVType = 0x000f |
| CDPTLVPower CDPTLVType = 0x0010 |
| CDPTLVMTU CDPTLVType = 0x0011 |
| CDPTLVExtendedTrust CDPTLVType = 0x0012 |
| CDPTLVUntrustedCOS CDPTLVType = 0x0013 |
| CDPTLVSysName CDPTLVType = 0x0014 |
| CDPTLVSysOID CDPTLVType = 0x0015 |
| CDPTLVMgmtAddresses CDPTLVType = 0x0016 |
| CDPTLVLocation CDPTLVType = 0x0017 |
| CDPTLVExternalPortID CDPTLVType = 0x0018 |
| CDPTLVPowerRequested CDPTLVType = 0x0019 |
| CDPTLVPowerAvailable CDPTLVType = 0x001a |
| CDPTLVPortUnidirectional CDPTLVType = 0x001b |
| CDPTLVEnergyWise CDPTLVType = 0x001d |
| CDPTLVSparePairPOE CDPTLVType = 0x001f |
| ) |
| |
| // CiscoDiscoveryValue is a TLV value inside a CiscoDiscovery packet layer. |
| type CiscoDiscoveryValue struct { |
| Type CDPTLVType |
| Length uint16 |
| Value []byte |
| } |
| |
| // CiscoDiscovery is a packet layer containing the Cisco Discovery Protocol. |
| // See http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm#31885 |
| type CiscoDiscovery struct { |
| BaseLayer |
| Version byte |
| TTL byte |
| Checksum uint16 |
| Values []CiscoDiscoveryValue |
| } |
| |
| // CDPCapability is the set of capabilities advertised by a CDP device. |
| type CDPCapability uint32 |
| |
| // CDPCapability values. |
| const ( |
| CDPCapMaskRouter CDPCapability = 0x0001 |
| CDPCapMaskTBBridge CDPCapability = 0x0002 |
| CDPCapMaskSPBridge CDPCapability = 0x0004 |
| CDPCapMaskSwitch CDPCapability = 0x0008 |
| CDPCapMaskHost CDPCapability = 0x0010 |
| CDPCapMaskIGMPFilter CDPCapability = 0x0020 |
| CDPCapMaskRepeater CDPCapability = 0x0040 |
| CDPCapMaskPhone CDPCapability = 0x0080 |
| CDPCapMaskRemote CDPCapability = 0x0100 |
| ) |
| |
| // CDPCapabilities represents the capabilities of a device |
| type CDPCapabilities struct { |
| L3Router bool |
| TBBridge bool |
| SPBridge bool |
| L2Switch bool |
| IsHost bool |
| IGMPFilter bool |
| L1Repeater bool |
| IsPhone bool |
| RemotelyManaged bool |
| } |
| |
| // CDP Power-over-Ethernet values. |
| const ( |
| CDPPoEFourWire byte = 0x01 |
| CDPPoEPDArch byte = 0x02 |
| CDPPoEPDRequest byte = 0x04 |
| CDPPoEPSE byte = 0x08 |
| ) |
| |
| // CDPSparePairPoE provides information on PoE. |
| type CDPSparePairPoE struct { |
| PSEFourWire bool // Supported / Not supported |
| PDArchShared bool // Shared / Independent |
| PDRequestOn bool // On / Off |
| PSEOn bool // On / Off |
| } |
| |
| // CDPVLANDialogue encapsulates a VLAN Query/Reply |
| type CDPVLANDialogue struct { |
| ID uint8 |
| VLAN uint16 |
| } |
| |
| // CDPPowerDialogue encapsulates a Power Query/Reply |
| type CDPPowerDialogue struct { |
| ID uint16 |
| MgmtID uint16 |
| Values []uint32 |
| } |
| |
| // CDPLocation provides location information for a CDP device. |
| type CDPLocation struct { |
| Type uint8 // Undocumented |
| Location string |
| } |
| |
| // CDPHello is a Cisco Hello message (undocumented, hence the "Unknown" fields) |
| type CDPHello struct { |
| OUI []byte |
| ProtocolID uint16 |
| ClusterMaster net.IP |
| Unknown1 net.IP |
| Version byte |
| SubVersion byte |
| Status byte |
| Unknown2 byte |
| ClusterCommander net.HardwareAddr |
| SwitchMAC net.HardwareAddr |
| Unknown3 byte |
| ManagementVLAN uint16 |
| } |
| |
| // CDPEnergyWiseSubtype is used within CDP to define TLV values. |
| type CDPEnergyWiseSubtype uint32 |
| |
| // CDPEnergyWiseSubtype values. |
| const ( |
| CDPEnergyWiseRole CDPEnergyWiseSubtype = 0x00000007 |
| CDPEnergyWiseDomain CDPEnergyWiseSubtype = 0x00000008 |
| CDPEnergyWiseName CDPEnergyWiseSubtype = 0x00000009 |
| CDPEnergyWiseReplyTo CDPEnergyWiseSubtype = 0x00000017 |
| ) |
| |
| // CDPEnergyWise is used by CDP to monitor and control power usage. |
| type CDPEnergyWise struct { |
| EncryptedData []byte |
| Unknown1 uint32 |
| SequenceNumber uint32 |
| ModelNumber string |
| Unknown2 uint16 |
| HardwareID string |
| SerialNum string |
| Unknown3 []byte |
| Role string |
| Domain string |
| Name string |
| ReplyUnknown1 []byte |
| ReplyPort []byte |
| ReplyAddress []byte |
| ReplyUnknown2 []byte |
| ReplyUnknown3 []byte |
| } |
| |
| // CiscoDiscoveryInfo represents the decoded details for a set of CiscoDiscoveryValues |
| type CiscoDiscoveryInfo struct { |
| BaseLayer |
| CDPHello |
| DeviceID string |
| Addresses []net.IP |
| PortID string |
| Capabilities CDPCapabilities |
| Version string |
| Platform string |
| IPPrefixes []net.IPNet |
| VTPDomain string |
| NativeVLAN uint16 |
| FullDuplex bool |
| VLANReply CDPVLANDialogue |
| VLANQuery CDPVLANDialogue |
| PowerConsumption uint16 |
| MTU uint32 |
| ExtendedTrust uint8 |
| UntrustedCOS uint8 |
| SysName string |
| SysOID string |
| MgmtAddresses []net.IP |
| Location CDPLocation |
| PowerRequest CDPPowerDialogue |
| PowerAvailable CDPPowerDialogue |
| SparePairPoe CDPSparePairPoE |
| EnergyWise CDPEnergyWise |
| Unknown []CiscoDiscoveryValue |
| } |
| |
| // LayerType returns gopacket.LayerTypeCiscoDiscovery. |
| func (c *CiscoDiscovery) LayerType() gopacket.LayerType { |
| return LayerTypeCiscoDiscovery |
| } |
| |
| func decodeCiscoDiscovery(data []byte, p gopacket.PacketBuilder) error { |
| c := &CiscoDiscovery{ |
| Version: data[0], |
| TTL: data[1], |
| Checksum: binary.BigEndian.Uint16(data[2:4]), |
| } |
| if c.Version != 1 && c.Version != 2 { |
| return fmt.Errorf("Invalid CiscoDiscovery version number %d", c.Version) |
| } |
| var err error |
| c.Values, err = decodeCiscoDiscoveryTLVs(data[4:]) |
| if err != nil { |
| return err |
| } |
| c.Contents = data[0:4] |
| c.Payload = data[4:] |
| p.AddLayer(c) |
| return p.NextDecoder(gopacket.DecodeFunc(decodeCiscoDiscoveryInfo)) |
| } |
| |
| // LayerType returns gopacket.LayerTypeCiscoDiscoveryInfo. |
| func (c *CiscoDiscoveryInfo) LayerType() gopacket.LayerType { |
| return LayerTypeCiscoDiscoveryInfo |
| } |
| |
| func decodeCiscoDiscoveryTLVs(data []byte) (values []CiscoDiscoveryValue, err error) { |
| for len(data) > 0 { |
| val := CiscoDiscoveryValue{ |
| Type: CDPTLVType(binary.BigEndian.Uint16(data[:2])), |
| Length: binary.BigEndian.Uint16(data[2:4]), |
| } |
| if val.Length < 4 { |
| err = fmt.Errorf("Invalid CiscoDiscovery value length %d", val.Length) |
| break |
| } |
| val.Value = data[4:val.Length] |
| values = append(values, val) |
| data = data[val.Length:] |
| } |
| return |
| } |
| |
| func decodeCiscoDiscoveryInfo(data []byte, p gopacket.PacketBuilder) error { |
| var err error |
| info := &CiscoDiscoveryInfo{BaseLayer: BaseLayer{Contents: data}} |
| p.AddLayer(info) |
| values, err := decodeCiscoDiscoveryTLVs(data) |
| if err != nil { // Unlikely, as parent decode will fail, but better safe... |
| return err |
| } |
| for _, val := range values { |
| switch val.Type { |
| case CDPTLVDevID: |
| info.DeviceID = string(val.Value) |
| case CDPTLVAddress: |
| if err = checkCDPTLVLen(val, 4); err != nil { |
| return err |
| } |
| info.Addresses, err = decodeAddresses(val.Value) |
| if err != nil { |
| return err |
| } |
| case CDPTLVPortID: |
| info.PortID = string(val.Value) |
| case CDPTLVCapabilities: |
| if err = checkCDPTLVLen(val, 4); err != nil { |
| return err |
| } |
| val := CDPCapability(binary.BigEndian.Uint32(val.Value[0:4])) |
| info.Capabilities.L3Router = (val&CDPCapMaskRouter > 0) |
| info.Capabilities.TBBridge = (val&CDPCapMaskTBBridge > 0) |
| info.Capabilities.SPBridge = (val&CDPCapMaskSPBridge > 0) |
| info.Capabilities.L2Switch = (val&CDPCapMaskSwitch > 0) |
| info.Capabilities.IsHost = (val&CDPCapMaskHost > 0) |
| info.Capabilities.IGMPFilter = (val&CDPCapMaskIGMPFilter > 0) |
| info.Capabilities.L1Repeater = (val&CDPCapMaskRepeater > 0) |
| info.Capabilities.IsPhone = (val&CDPCapMaskPhone > 0) |
| info.Capabilities.RemotelyManaged = (val&CDPCapMaskRemote > 0) |
| case CDPTLVVersion: |
| info.Version = string(val.Value) |
| case CDPTLVPlatform: |
| info.Platform = string(val.Value) |
| case CDPTLVIPPrefix: |
| v := val.Value |
| l := len(v) |
| if l%5 == 0 && l >= 5 { |
| for len(v) > 0 { |
| _, ipnet, _ := net.ParseCIDR(fmt.Sprintf("%d.%d.%d.%d/%d", v[0], v[1], v[2], v[3], v[4])) |
| info.IPPrefixes = append(info.IPPrefixes, *ipnet) |
| v = v[5:] |
| } |
| } else { |
| return fmt.Errorf("Invalid TLV %v length %d", val.Type, len(val.Value)) |
| } |
| case CDPTLVHello: |
| if err = checkCDPTLVLen(val, 32); err != nil { |
| return err |
| } |
| v := val.Value |
| info.CDPHello.OUI = v[0:3] |
| info.CDPHello.ProtocolID = binary.BigEndian.Uint16(v[3:5]) |
| info.CDPHello.ClusterMaster = v[5:9] |
| info.CDPHello.Unknown1 = v[9:13] |
| info.CDPHello.Version = v[13] |
| info.CDPHello.SubVersion = v[14] |
| info.CDPHello.Status = v[15] |
| info.CDPHello.Unknown2 = v[16] |
| info.CDPHello.ClusterCommander = v[17:23] |
| info.CDPHello.SwitchMAC = v[23:29] |
| info.CDPHello.Unknown3 = v[29] |
| info.CDPHello.ManagementVLAN = binary.BigEndian.Uint16(v[30:32]) |
| case CDPTLVVTPDomain: |
| info.VTPDomain = string(val.Value) |
| case CDPTLVNativeVLAN: |
| if err = checkCDPTLVLen(val, 2); err != nil { |
| return err |
| } |
| info.NativeVLAN = binary.BigEndian.Uint16(val.Value[0:2]) |
| case CDPTLVFullDuplex: |
| if err = checkCDPTLVLen(val, 1); err != nil { |
| return err |
| } |
| info.FullDuplex = (val.Value[0] == 1) |
| case CDPTLVVLANReply: |
| if err = checkCDPTLVLen(val, 3); err != nil { |
| return err |
| } |
| info.VLANReply.ID = uint8(val.Value[0]) |
| info.VLANReply.VLAN = binary.BigEndian.Uint16(val.Value[1:3]) |
| case CDPTLVVLANQuery: |
| if err = checkCDPTLVLen(val, 3); err != nil { |
| return err |
| } |
| info.VLANQuery.ID = uint8(val.Value[0]) |
| info.VLANQuery.VLAN = binary.BigEndian.Uint16(val.Value[1:3]) |
| case CDPTLVPower: |
| if err = checkCDPTLVLen(val, 2); err != nil { |
| return err |
| } |
| info.PowerConsumption = binary.BigEndian.Uint16(val.Value[0:2]) |
| case CDPTLVMTU: |
| if err = checkCDPTLVLen(val, 4); err != nil { |
| return err |
| } |
| info.MTU = binary.BigEndian.Uint32(val.Value[0:4]) |
| case CDPTLVExtendedTrust: |
| if err = checkCDPTLVLen(val, 1); err != nil { |
| return err |
| } |
| info.ExtendedTrust = uint8(val.Value[0]) |
| case CDPTLVUntrustedCOS: |
| if err = checkCDPTLVLen(val, 1); err != nil { |
| return err |
| } |
| info.UntrustedCOS = uint8(val.Value[0]) |
| case CDPTLVSysName: |
| info.SysName = string(val.Value) |
| case CDPTLVSysOID: |
| info.SysOID = string(val.Value) |
| case CDPTLVMgmtAddresses: |
| if err = checkCDPTLVLen(val, 4); err != nil { |
| return err |
| } |
| info.MgmtAddresses, err = decodeAddresses(val.Value) |
| if err != nil { |
| return err |
| } |
| case CDPTLVLocation: |
| if err = checkCDPTLVLen(val, 2); err != nil { |
| return err |
| } |
| info.Location.Type = uint8(val.Value[0]) |
| info.Location.Location = string(val.Value[1:]) |
| |
| // case CDPTLVLExternalPortID: |
| // Undocumented |
| case CDPTLVPowerRequested: |
| if err = checkCDPTLVLen(val, 4); err != nil { |
| return err |
| } |
| info.PowerRequest.ID = binary.BigEndian.Uint16(val.Value[0:2]) |
| info.PowerRequest.MgmtID = binary.BigEndian.Uint16(val.Value[2:4]) |
| for n := 4; n < len(val.Value); n += 4 { |
| info.PowerRequest.Values = append(info.PowerRequest.Values, binary.BigEndian.Uint32(val.Value[n:n+4])) |
| } |
| case CDPTLVPowerAvailable: |
| if err = checkCDPTLVLen(val, 4); err != nil { |
| return err |
| } |
| info.PowerAvailable.ID = binary.BigEndian.Uint16(val.Value[0:2]) |
| info.PowerAvailable.MgmtID = binary.BigEndian.Uint16(val.Value[2:4]) |
| for n := 4; n < len(val.Value); n += 4 { |
| info.PowerAvailable.Values = append(info.PowerAvailable.Values, binary.BigEndian.Uint32(val.Value[n:n+4])) |
| } |
| // case CDPTLVPortUnidirectional |
| // Undocumented |
| case CDPTLVEnergyWise: |
| if err = checkCDPTLVLen(val, 72); err != nil { |
| return err |
| } |
| info.EnergyWise.EncryptedData = val.Value[0:20] |
| info.EnergyWise.Unknown1 = binary.BigEndian.Uint32(val.Value[20:24]) |
| info.EnergyWise.SequenceNumber = binary.BigEndian.Uint32(val.Value[24:28]) |
| info.EnergyWise.ModelNumber = string(val.Value[28:44]) |
| info.EnergyWise.Unknown2 = binary.BigEndian.Uint16(val.Value[44:46]) |
| info.EnergyWise.HardwareID = string(val.Value[46:49]) |
| info.EnergyWise.SerialNum = string(val.Value[49:60]) |
| info.EnergyWise.Unknown3 = val.Value[60:68] |
| tlvLen := binary.BigEndian.Uint16(val.Value[68:70]) |
| tlvNum := binary.BigEndian.Uint16(val.Value[70:72]) |
| data := val.Value[72:] |
| if len(data) < int(tlvLen) { |
| return fmt.Errorf("Invalid TLV length %d vs %d", tlvLen, len(data)) |
| } |
| numSeen := 0 |
| for len(data) > 8 { |
| numSeen++ |
| if numSeen > int(tlvNum) { // Too many TLV's ? |
| return fmt.Errorf("Too many TLV's - wanted %d, saw %d", tlvNum, numSeen) |
| } |
| tType := CDPEnergyWiseSubtype(binary.BigEndian.Uint32(data[0:4])) |
| tLen := int(binary.BigEndian.Uint32(data[4:8])) |
| if tLen > len(data)-8 { |
| return fmt.Errorf("Invalid TLV length %d vs %d", tLen, len(data)-8) |
| } |
| data = data[8:] |
| switch tType { |
| case CDPEnergyWiseRole: |
| info.EnergyWise.Role = string(data[:]) |
| case CDPEnergyWiseDomain: |
| info.EnergyWise.Domain = string(data[:]) |
| case CDPEnergyWiseName: |
| info.EnergyWise.Name = string(data[:]) |
| case CDPEnergyWiseReplyTo: |
| if len(data) >= 18 { |
| info.EnergyWise.ReplyUnknown1 = data[0:2] |
| info.EnergyWise.ReplyPort = data[2:4] |
| info.EnergyWise.ReplyAddress = data[4:8] |
| info.EnergyWise.ReplyUnknown2 = data[8:10] |
| info.EnergyWise.ReplyUnknown3 = data[10:14] |
| } |
| } |
| data = data[tLen:] |
| } |
| case CDPTLVSparePairPOE: |
| if err = checkCDPTLVLen(val, 1); err != nil { |
| return err |
| } |
| v := val.Value[0] |
| info.SparePairPoe.PSEFourWire = (v&CDPPoEFourWire > 0) |
| info.SparePairPoe.PDArchShared = (v&CDPPoEPDArch > 0) |
| info.SparePairPoe.PDRequestOn = (v&CDPPoEPDRequest > 0) |
| info.SparePairPoe.PSEOn = (v&CDPPoEPSE > 0) |
| default: |
| info.Unknown = append(info.Unknown, val) |
| } |
| } |
| return nil |
| } |
| |
| // CDP Protocol Types |
| const ( |
| CDPProtocolTypeNLPID byte = 1 |
| CDPProtocolType802_2 byte = 2 |
| ) |
| |
| // CDPAddressType is used to define TLV values within CDP addresses. |
| type CDPAddressType uint64 |
| |
| // CDP Address types. |
| const ( |
| CDPAddressTypeCLNP CDPAddressType = 0x81 |
| CDPAddressTypeIPV4 CDPAddressType = 0xcc |
| CDPAddressTypeIPV6 CDPAddressType = 0xaaaa030000000800 |
| CDPAddressTypeDECNET CDPAddressType = 0xaaaa030000006003 |
| CDPAddressTypeAPPLETALK CDPAddressType = 0xaaaa03000000809b |
| CDPAddressTypeIPX CDPAddressType = 0xaaaa030000008137 |
| CDPAddressTypeVINES CDPAddressType = 0xaaaa0300000080c4 |
| CDPAddressTypeXNS CDPAddressType = 0xaaaa030000000600 |
| CDPAddressTypeAPOLLO CDPAddressType = 0xaaaa030000008019 |
| ) |
| |
| func decodeAddresses(v []byte) (addresses []net.IP, err error) { |
| numaddr := int(binary.BigEndian.Uint32(v[0:4])) |
| if numaddr < 1 { |
| return nil, fmt.Errorf("Invalid Address TLV number %d", numaddr) |
| } |
| v = v[4:] |
| if len(v) < numaddr*8 { |
| return nil, fmt.Errorf("Invalid Address TLV length %d", len(v)) |
| } |
| for i := 0; i < numaddr; i++ { |
| prottype := v[0] |
| if prottype != CDPProtocolTypeNLPID && prottype != CDPProtocolType802_2 { // invalid protocol type |
| return nil, fmt.Errorf("Invalid Address Protocol %d", prottype) |
| } |
| protlen := int(v[1]) |
| if (prottype == CDPProtocolTypeNLPID && protlen != 1) || |
| (prottype == CDPProtocolType802_2 && protlen != 3 && protlen != 8) { // invalid length |
| return nil, fmt.Errorf("Invalid Address Protocol length %d", protlen) |
| } |
| plen := make([]byte, 8) |
| copy(plen[8-protlen:], v[2:2+protlen]) |
| protocol := CDPAddressType(binary.BigEndian.Uint64(plen)) |
| v = v[2+protlen:] |
| addrlen := binary.BigEndian.Uint16(v[0:2]) |
| ab := v[2 : 2+addrlen] |
| if protocol == CDPAddressTypeIPV4 && addrlen == 4 { |
| addresses = append(addresses, net.IPv4(ab[0], ab[1], ab[2], ab[3])) |
| } else if protocol == CDPAddressTypeIPV6 && addrlen == 16 { |
| addresses = append(addresses, net.IP(ab)) |
| } else { |
| // only handle IPV4 & IPV6 for now |
| } |
| v = v[2+addrlen:] |
| if len(v) < 8 { |
| break |
| } |
| } |
| return |
| } |
| |
| func (t CDPTLVType) String() (s string) { |
| switch t { |
| case CDPTLVDevID: |
| s = "Device ID" |
| case CDPTLVAddress: |
| s = "Addresses" |
| case CDPTLVPortID: |
| s = "Port ID" |
| case CDPTLVCapabilities: |
| s = "Capabilities" |
| case CDPTLVVersion: |
| s = "Software Version" |
| case CDPTLVPlatform: |
| s = "Platform" |
| case CDPTLVIPPrefix: |
| s = "IP Prefix" |
| case CDPTLVHello: |
| s = "Protocol Hello" |
| case CDPTLVVTPDomain: |
| s = "VTP Management Domain" |
| case CDPTLVNativeVLAN: |
| s = "Native VLAN" |
| case CDPTLVFullDuplex: |
| s = "Full Duplex" |
| case CDPTLVVLANReply: |
| s = "VoIP VLAN Reply" |
| case CDPTLVVLANQuery: |
| s = "VLANQuery" |
| case CDPTLVPower: |
| s = "Power consumption" |
| case CDPTLVMTU: |
| s = "MTU" |
| case CDPTLVExtendedTrust: |
| s = "Extended Trust Bitmap" |
| case CDPTLVUntrustedCOS: |
| s = "Untrusted Port CoS" |
| case CDPTLVSysName: |
| s = "System Name" |
| case CDPTLVSysOID: |
| s = "System OID" |
| case CDPTLVMgmtAddresses: |
| s = "Management Addresses" |
| case CDPTLVLocation: |
| s = "Location" |
| case CDPTLVExternalPortID: |
| s = "External Port ID" |
| case CDPTLVPowerRequested: |
| s = "Power Requested" |
| case CDPTLVPowerAvailable: |
| s = "Power Available" |
| case CDPTLVPortUnidirectional: |
| s = "Port Unidirectional" |
| case CDPTLVEnergyWise: |
| s = "Energy Wise" |
| case CDPTLVSparePairPOE: |
| s = "Spare Pair POE" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (a CDPAddressType) String() (s string) { |
| switch a { |
| case CDPAddressTypeCLNP: |
| s = "Connectionless Network Protocol" |
| case CDPAddressTypeIPV4: |
| s = "IPv4" |
| case CDPAddressTypeIPV6: |
| s = "IPv6" |
| case CDPAddressTypeDECNET: |
| s = "DECnet Phase IV" |
| case CDPAddressTypeAPPLETALK: |
| s = "Apple Talk" |
| case CDPAddressTypeIPX: |
| s = "Novell IPX" |
| case CDPAddressTypeVINES: |
| s = "Banyan VINES" |
| case CDPAddressTypeXNS: |
| s = "Xerox Network Systems" |
| case CDPAddressTypeAPOLLO: |
| s = "Apollo" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func (t CDPEnergyWiseSubtype) String() (s string) { |
| switch t { |
| case CDPEnergyWiseRole: |
| s = "Role" |
| case CDPEnergyWiseDomain: |
| s = "Domain" |
| case CDPEnergyWiseName: |
| s = "Name" |
| case CDPEnergyWiseReplyTo: |
| s = "ReplyTo" |
| default: |
| s = "Unknown" |
| } |
| return |
| } |
| |
| func checkCDPTLVLen(v CiscoDiscoveryValue, l int) (err error) { |
| if len(v.Value) < l { |
| err = fmt.Errorf("Invalid TLV %v length %d", v.Type, len(v.Value)) |
| } |
| return |
| } |