github.com/gopacket/gopacket@v1.1.0/layers/cdp.go (about) 1 // Copyright 2012 Google, Inc. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file in the root of the source 5 // tree. 6 7 // Enum types courtesy of... 8 // http://search.cpan.org/~mchapman/Net-CDP-0.09/lib/Net/CDP.pm 9 // https://code.google.com/p/ladvd/ 10 // http://anonsvn.wireshark.org/viewvc/releases/wireshark-1.8.6/epan/dissectors/packet-cdp.c 11 12 package layers 13 14 import ( 15 "encoding/binary" 16 "errors" 17 "fmt" 18 "net" 19 20 "github.com/gopacket/gopacket" 21 ) 22 23 // CDPTLVType is the type of each TLV value in a CiscoDiscovery packet. 24 type CDPTLVType uint16 25 26 // CDPTLVType values. 27 const ( 28 CDPTLVDevID CDPTLVType = 0x0001 29 CDPTLVAddress CDPTLVType = 0x0002 30 CDPTLVPortID CDPTLVType = 0x0003 31 CDPTLVCapabilities CDPTLVType = 0x0004 32 CDPTLVVersion CDPTLVType = 0x0005 33 CDPTLVPlatform CDPTLVType = 0x0006 34 CDPTLVIPPrefix CDPTLVType = 0x0007 35 CDPTLVHello CDPTLVType = 0x0008 36 CDPTLVVTPDomain CDPTLVType = 0x0009 37 CDPTLVNativeVLAN CDPTLVType = 0x000a 38 CDPTLVFullDuplex CDPTLVType = 0x000b 39 CDPTLVVLANReply CDPTLVType = 0x000e 40 CDPTLVVLANQuery CDPTLVType = 0x000f 41 CDPTLVPower CDPTLVType = 0x0010 42 CDPTLVMTU CDPTLVType = 0x0011 43 CDPTLVExtendedTrust CDPTLVType = 0x0012 44 CDPTLVUntrustedCOS CDPTLVType = 0x0013 45 CDPTLVSysName CDPTLVType = 0x0014 46 CDPTLVSysOID CDPTLVType = 0x0015 47 CDPTLVMgmtAddresses CDPTLVType = 0x0016 48 CDPTLVLocation CDPTLVType = 0x0017 49 CDPTLVExternalPortID CDPTLVType = 0x0018 50 CDPTLVPowerRequested CDPTLVType = 0x0019 51 CDPTLVPowerAvailable CDPTLVType = 0x001a 52 CDPTLVPortUnidirectional CDPTLVType = 0x001b 53 CDPTLVEnergyWise CDPTLVType = 0x001d 54 CDPTLVSparePairPOE CDPTLVType = 0x001f 55 ) 56 57 // CiscoDiscoveryValue is a TLV value inside a CiscoDiscovery packet layer. 58 type CiscoDiscoveryValue struct { 59 Type CDPTLVType 60 Length uint16 61 Value []byte 62 } 63 64 // CiscoDiscovery is a packet layer containing the Cisco Discovery Protocol. 65 // See http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm#31885 66 type CiscoDiscovery struct { 67 BaseLayer 68 Version byte 69 TTL byte 70 Checksum uint16 71 Values []CiscoDiscoveryValue 72 } 73 74 // CDPCapability is the set of capabilities advertised by a CDP device. 75 type CDPCapability uint32 76 77 // CDPCapability values. 78 const ( 79 CDPCapMaskRouter CDPCapability = 0x0001 80 CDPCapMaskTBBridge CDPCapability = 0x0002 81 CDPCapMaskSPBridge CDPCapability = 0x0004 82 CDPCapMaskSwitch CDPCapability = 0x0008 83 CDPCapMaskHost CDPCapability = 0x0010 84 CDPCapMaskIGMPFilter CDPCapability = 0x0020 85 CDPCapMaskRepeater CDPCapability = 0x0040 86 CDPCapMaskPhone CDPCapability = 0x0080 87 CDPCapMaskRemote CDPCapability = 0x0100 88 ) 89 90 // CDPCapabilities represents the capabilities of a device 91 type CDPCapabilities struct { 92 L3Router bool 93 TBBridge bool 94 SPBridge bool 95 L2Switch bool 96 IsHost bool 97 IGMPFilter bool 98 L1Repeater bool 99 IsPhone bool 100 RemotelyManaged bool 101 } 102 103 // CDP Power-over-Ethernet values. 104 const ( 105 CDPPoEFourWire byte = 0x01 106 CDPPoEPDArch byte = 0x02 107 CDPPoEPDRequest byte = 0x04 108 CDPPoEPSE byte = 0x08 109 ) 110 111 // CDPSparePairPoE provides information on PoE. 112 type CDPSparePairPoE struct { 113 PSEFourWire bool // Supported / Not supported 114 PDArchShared bool // Shared / Independent 115 PDRequestOn bool // On / Off 116 PSEOn bool // On / Off 117 } 118 119 // CDPVLANDialogue encapsulates a VLAN Query/Reply 120 type CDPVLANDialogue struct { 121 ID uint8 122 VLAN uint16 123 } 124 125 // CDPPowerDialogue encapsulates a Power Query/Reply 126 type CDPPowerDialogue struct { 127 ID uint16 128 MgmtID uint16 129 Values []uint32 130 } 131 132 // CDPLocation provides location information for a CDP device. 133 type CDPLocation struct { 134 Type uint8 // Undocumented 135 Location string 136 } 137 138 // CDPHello is a Cisco Hello message (undocumented, hence the "Unknown" fields) 139 type CDPHello struct { 140 OUI []byte 141 ProtocolID uint16 142 ClusterMaster net.IP 143 Unknown1 net.IP 144 Version byte 145 SubVersion byte 146 Status byte 147 Unknown2 byte 148 ClusterCommander net.HardwareAddr 149 SwitchMAC net.HardwareAddr 150 Unknown3 byte 151 ManagementVLAN uint16 152 } 153 154 // CDPEnergyWiseSubtype is used within CDP to define TLV values. 155 type CDPEnergyWiseSubtype uint32 156 157 // CDPEnergyWiseSubtype values. 158 const ( 159 CDPEnergyWiseRole CDPEnergyWiseSubtype = 0x00000007 160 CDPEnergyWiseDomain CDPEnergyWiseSubtype = 0x00000008 161 CDPEnergyWiseName CDPEnergyWiseSubtype = 0x00000009 162 CDPEnergyWiseReplyTo CDPEnergyWiseSubtype = 0x00000017 163 ) 164 165 // CDPEnergyWise is used by CDP to monitor and control power usage. 166 type CDPEnergyWise struct { 167 EncryptedData []byte 168 Unknown1 uint32 169 SequenceNumber uint32 170 ModelNumber string 171 Unknown2 uint16 172 HardwareID string 173 SerialNum string 174 Unknown3 []byte 175 Role string 176 Domain string 177 Name string 178 ReplyUnknown1 []byte 179 ReplyPort []byte 180 ReplyAddress []byte 181 ReplyUnknown2 []byte 182 ReplyUnknown3 []byte 183 } 184 185 // CiscoDiscoveryInfo represents the decoded details for a set of CiscoDiscoveryValues 186 type CiscoDiscoveryInfo struct { 187 BaseLayer 188 CDPHello 189 DeviceID string 190 Addresses []net.IP 191 PortID string 192 Capabilities CDPCapabilities 193 Version string 194 Platform string 195 IPPrefixes []net.IPNet 196 VTPDomain string 197 NativeVLAN uint16 198 FullDuplex bool 199 VLANReply CDPVLANDialogue 200 VLANQuery CDPVLANDialogue 201 PowerConsumption uint16 202 MTU uint32 203 ExtendedTrust uint8 204 UntrustedCOS uint8 205 SysName string 206 SysOID string 207 MgmtAddresses []net.IP 208 Location CDPLocation 209 PowerRequest CDPPowerDialogue 210 PowerAvailable CDPPowerDialogue 211 SparePairPoe CDPSparePairPoE 212 EnergyWise CDPEnergyWise 213 Unknown []CiscoDiscoveryValue 214 } 215 216 // LayerType returns gopacket.LayerTypeCiscoDiscovery. 217 func (c *CiscoDiscovery) LayerType() gopacket.LayerType { 218 return LayerTypeCiscoDiscovery 219 } 220 221 func decodeCiscoDiscovery(data []byte, p gopacket.PacketBuilder) error { 222 c := &CiscoDiscovery{ 223 Version: data[0], 224 TTL: data[1], 225 Checksum: binary.BigEndian.Uint16(data[2:4]), 226 } 227 if c.Version != 1 && c.Version != 2 { 228 return fmt.Errorf("Invalid CiscoDiscovery version number %d", c.Version) 229 } 230 var err error 231 c.Values, err = decodeCiscoDiscoveryTLVs(data[4:], p) 232 if err != nil { 233 return err 234 } 235 c.Contents = data[0:4] 236 c.Payload = data[4:] 237 p.AddLayer(c) 238 return p.NextDecoder(gopacket.DecodeFunc(decodeCiscoDiscoveryInfo)) 239 } 240 241 // LayerType returns gopacket.LayerTypeCiscoDiscoveryInfo. 242 func (c *CiscoDiscoveryInfo) LayerType() gopacket.LayerType { 243 return LayerTypeCiscoDiscoveryInfo 244 } 245 246 func decodeCiscoDiscoveryTLVs(data []byte, p gopacket.PacketBuilder) (values []CiscoDiscoveryValue, err error) { 247 for len(data) > 0 { 248 if len(data) < 4 { 249 p.SetTruncated() 250 return nil, errors.New("CDP TLV < 4 bytes") 251 } 252 val := CiscoDiscoveryValue{ 253 Type: CDPTLVType(binary.BigEndian.Uint16(data[:2])), 254 Length: binary.BigEndian.Uint16(data[2:4]), 255 } 256 if val.Length < 4 { 257 err = fmt.Errorf("Invalid CiscoDiscovery value length %d", val.Length) 258 break 259 } else if len(data) < int(val.Length) { 260 p.SetTruncated() 261 return nil, fmt.Errorf("CDP TLV < length %d", val.Length) 262 } 263 val.Value = data[4:val.Length] 264 values = append(values, val) 265 data = data[val.Length:] 266 } 267 return 268 } 269 270 func decodeCiscoDiscoveryInfo(data []byte, p gopacket.PacketBuilder) error { 271 var err error 272 info := &CiscoDiscoveryInfo{BaseLayer: BaseLayer{Contents: data}} 273 p.AddLayer(info) 274 values, err := decodeCiscoDiscoveryTLVs(data, p) 275 if err != nil { // Unlikely, as parent decode will fail, but better safe... 276 return err 277 } 278 for _, val := range values { 279 switch val.Type { 280 case CDPTLVDevID: 281 info.DeviceID = string(val.Value) 282 case CDPTLVAddress: 283 if err = checkCDPTLVLen(val, 4); err != nil { 284 return err 285 } 286 info.Addresses, err = decodeAddresses(val.Value) 287 if err != nil { 288 return err 289 } 290 case CDPTLVPortID: 291 info.PortID = string(val.Value) 292 case CDPTLVCapabilities: 293 if err = checkCDPTLVLen(val, 4); err != nil { 294 return err 295 } 296 val := CDPCapability(binary.BigEndian.Uint32(val.Value[0:4])) 297 info.Capabilities.L3Router = (val&CDPCapMaskRouter > 0) 298 info.Capabilities.TBBridge = (val&CDPCapMaskTBBridge > 0) 299 info.Capabilities.SPBridge = (val&CDPCapMaskSPBridge > 0) 300 info.Capabilities.L2Switch = (val&CDPCapMaskSwitch > 0) 301 info.Capabilities.IsHost = (val&CDPCapMaskHost > 0) 302 info.Capabilities.IGMPFilter = (val&CDPCapMaskIGMPFilter > 0) 303 info.Capabilities.L1Repeater = (val&CDPCapMaskRepeater > 0) 304 info.Capabilities.IsPhone = (val&CDPCapMaskPhone > 0) 305 info.Capabilities.RemotelyManaged = (val&CDPCapMaskRemote > 0) 306 case CDPTLVVersion: 307 info.Version = string(val.Value) 308 case CDPTLVPlatform: 309 info.Platform = string(val.Value) 310 case CDPTLVIPPrefix: 311 v := val.Value 312 l := len(v) 313 if l%5 == 0 && l >= 5 { 314 for len(v) > 0 { 315 _, ipnet, _ := net.ParseCIDR(fmt.Sprintf("%d.%d.%d.%d/%d", v[0], v[1], v[2], v[3], v[4])) 316 info.IPPrefixes = append(info.IPPrefixes, *ipnet) 317 v = v[5:] 318 } 319 } else { 320 return fmt.Errorf("Invalid TLV %v length %d", val.Type, len(val.Value)) 321 } 322 case CDPTLVHello: 323 if err = checkCDPTLVLen(val, 32); err != nil { 324 return err 325 } 326 v := val.Value 327 info.CDPHello.OUI = v[0:3] 328 info.CDPHello.ProtocolID = binary.BigEndian.Uint16(v[3:5]) 329 info.CDPHello.ClusterMaster = v[5:9] 330 info.CDPHello.Unknown1 = v[9:13] 331 info.CDPHello.Version = v[13] 332 info.CDPHello.SubVersion = v[14] 333 info.CDPHello.Status = v[15] 334 info.CDPHello.Unknown2 = v[16] 335 info.CDPHello.ClusterCommander = v[17:23] 336 info.CDPHello.SwitchMAC = v[23:29] 337 info.CDPHello.Unknown3 = v[29] 338 info.CDPHello.ManagementVLAN = binary.BigEndian.Uint16(v[30:32]) 339 case CDPTLVVTPDomain: 340 info.VTPDomain = string(val.Value) 341 case CDPTLVNativeVLAN: 342 if err = checkCDPTLVLen(val, 2); err != nil { 343 return err 344 } 345 info.NativeVLAN = binary.BigEndian.Uint16(val.Value[0:2]) 346 case CDPTLVFullDuplex: 347 if err = checkCDPTLVLen(val, 1); err != nil { 348 return err 349 } 350 info.FullDuplex = (val.Value[0] == 1) 351 case CDPTLVVLANReply: 352 if err = checkCDPTLVLen(val, 3); err != nil { 353 return err 354 } 355 info.VLANReply.ID = uint8(val.Value[0]) 356 info.VLANReply.VLAN = binary.BigEndian.Uint16(val.Value[1:3]) 357 case CDPTLVVLANQuery: 358 if err = checkCDPTLVLen(val, 3); err != nil { 359 return err 360 } 361 info.VLANQuery.ID = uint8(val.Value[0]) 362 info.VLANQuery.VLAN = binary.BigEndian.Uint16(val.Value[1:3]) 363 case CDPTLVPower: 364 if err = checkCDPTLVLen(val, 2); err != nil { 365 return err 366 } 367 info.PowerConsumption = binary.BigEndian.Uint16(val.Value[0:2]) 368 case CDPTLVMTU: 369 if err = checkCDPTLVLen(val, 4); err != nil { 370 return err 371 } 372 info.MTU = binary.BigEndian.Uint32(val.Value[0:4]) 373 case CDPTLVExtendedTrust: 374 if err = checkCDPTLVLen(val, 1); err != nil { 375 return err 376 } 377 info.ExtendedTrust = uint8(val.Value[0]) 378 case CDPTLVUntrustedCOS: 379 if err = checkCDPTLVLen(val, 1); err != nil { 380 return err 381 } 382 info.UntrustedCOS = uint8(val.Value[0]) 383 case CDPTLVSysName: 384 info.SysName = string(val.Value) 385 case CDPTLVSysOID: 386 info.SysOID = string(val.Value) 387 case CDPTLVMgmtAddresses: 388 if err = checkCDPTLVLen(val, 4); err != nil { 389 return err 390 } 391 info.MgmtAddresses, err = decodeAddresses(val.Value) 392 if err != nil { 393 return err 394 } 395 case CDPTLVLocation: 396 if err = checkCDPTLVLen(val, 2); err != nil { 397 return err 398 } 399 info.Location.Type = uint8(val.Value[0]) 400 info.Location.Location = string(val.Value[1:]) 401 402 // case CDPTLVLExternalPortID: 403 // Undocumented 404 case CDPTLVPowerRequested: 405 if err = checkCDPTLVLen(val, 4); err != nil { 406 return err 407 } 408 info.PowerRequest.ID = binary.BigEndian.Uint16(val.Value[0:2]) 409 info.PowerRequest.MgmtID = binary.BigEndian.Uint16(val.Value[2:4]) 410 for n := 4; n < len(val.Value); n += 4 { 411 info.PowerRequest.Values = append(info.PowerRequest.Values, binary.BigEndian.Uint32(val.Value[n:n+4])) 412 } 413 case CDPTLVPowerAvailable: 414 if err = checkCDPTLVLen(val, 4); err != nil { 415 return err 416 } 417 info.PowerAvailable.ID = binary.BigEndian.Uint16(val.Value[0:2]) 418 info.PowerAvailable.MgmtID = binary.BigEndian.Uint16(val.Value[2:4]) 419 for n := 4; n < len(val.Value); n += 4 { 420 info.PowerAvailable.Values = append(info.PowerAvailable.Values, binary.BigEndian.Uint32(val.Value[n:n+4])) 421 } 422 // case CDPTLVPortUnidirectional 423 // Undocumented 424 case CDPTLVEnergyWise: 425 if err = checkCDPTLVLen(val, 72); err != nil { 426 return err 427 } 428 info.EnergyWise.EncryptedData = val.Value[0:20] 429 info.EnergyWise.Unknown1 = binary.BigEndian.Uint32(val.Value[20:24]) 430 info.EnergyWise.SequenceNumber = binary.BigEndian.Uint32(val.Value[24:28]) 431 info.EnergyWise.ModelNumber = string(val.Value[28:44]) 432 info.EnergyWise.Unknown2 = binary.BigEndian.Uint16(val.Value[44:46]) 433 info.EnergyWise.HardwareID = string(val.Value[46:49]) 434 info.EnergyWise.SerialNum = string(val.Value[49:60]) 435 info.EnergyWise.Unknown3 = val.Value[60:68] 436 tlvLen := binary.BigEndian.Uint16(val.Value[68:70]) 437 tlvNum := binary.BigEndian.Uint16(val.Value[70:72]) 438 data := val.Value[72:] 439 if len(data) < int(tlvLen) { 440 return fmt.Errorf("Invalid TLV length %d vs %d", tlvLen, len(data)) 441 } 442 numSeen := 0 443 for len(data) > 8 { 444 numSeen++ 445 if numSeen > int(tlvNum) { // Too many TLV's ? 446 return fmt.Errorf("Too many TLV's - wanted %d, saw %d", tlvNum, numSeen) 447 } 448 tType := CDPEnergyWiseSubtype(binary.BigEndian.Uint32(data[0:4])) 449 tLen := int(binary.BigEndian.Uint32(data[4:8])) 450 if tLen > len(data)-8 { 451 return fmt.Errorf("Invalid TLV length %d vs %d", tLen, len(data)-8) 452 } 453 data = data[8:] 454 switch tType { 455 case CDPEnergyWiseRole: 456 info.EnergyWise.Role = string(data[:]) 457 case CDPEnergyWiseDomain: 458 info.EnergyWise.Domain = string(data[:]) 459 case CDPEnergyWiseName: 460 info.EnergyWise.Name = string(data[:]) 461 case CDPEnergyWiseReplyTo: 462 if len(data) >= 18 { 463 info.EnergyWise.ReplyUnknown1 = data[0:2] 464 info.EnergyWise.ReplyPort = data[2:4] 465 info.EnergyWise.ReplyAddress = data[4:8] 466 info.EnergyWise.ReplyUnknown2 = data[8:10] 467 info.EnergyWise.ReplyUnknown3 = data[10:14] 468 } 469 } 470 data = data[tLen:] 471 } 472 case CDPTLVSparePairPOE: 473 if err = checkCDPTLVLen(val, 1); err != nil { 474 return err 475 } 476 v := val.Value[0] 477 info.SparePairPoe.PSEFourWire = (v&CDPPoEFourWire > 0) 478 info.SparePairPoe.PDArchShared = (v&CDPPoEPDArch > 0) 479 info.SparePairPoe.PDRequestOn = (v&CDPPoEPDRequest > 0) 480 info.SparePairPoe.PSEOn = (v&CDPPoEPSE > 0) 481 default: 482 info.Unknown = append(info.Unknown, val) 483 } 484 } 485 return nil 486 } 487 488 // CDP Protocol Types 489 const ( 490 CDPProtocolTypeNLPID byte = 1 491 CDPProtocolType802_2 byte = 2 492 ) 493 494 // CDPAddressType is used to define TLV values within CDP addresses. 495 type CDPAddressType uint64 496 497 // CDP Address types. 498 const ( 499 CDPAddressTypeCLNP CDPAddressType = 0x81 500 CDPAddressTypeIPV4 CDPAddressType = 0xcc 501 CDPAddressTypeIPV6 CDPAddressType = 0xaaaa030000000800 502 CDPAddressTypeDECNET CDPAddressType = 0xaaaa030000006003 503 CDPAddressTypeAPPLETALK CDPAddressType = 0xaaaa03000000809b 504 CDPAddressTypeIPX CDPAddressType = 0xaaaa030000008137 505 CDPAddressTypeVINES CDPAddressType = 0xaaaa0300000080c4 506 CDPAddressTypeXNS CDPAddressType = 0xaaaa030000000600 507 CDPAddressTypeAPOLLO CDPAddressType = 0xaaaa030000008019 508 ) 509 510 func decodeAddresses(v []byte) (addresses []net.IP, err error) { 511 numaddr := int(binary.BigEndian.Uint32(v[0:4])) 512 if numaddr < 1 { 513 return nil, fmt.Errorf("Invalid Address TLV number %d", numaddr) 514 } 515 v = v[4:] 516 if len(v) < numaddr*8 { 517 return nil, fmt.Errorf("Invalid Address TLV length %d", len(v)) 518 } 519 for i := 0; i < numaddr; i++ { 520 prottype := v[0] 521 if prottype != CDPProtocolTypeNLPID && prottype != CDPProtocolType802_2 { // invalid protocol type 522 return nil, fmt.Errorf("Invalid Address Protocol %d", prottype) 523 } 524 protlen := int(v[1]) 525 if (prottype == CDPProtocolTypeNLPID && protlen != 1) || 526 (prottype == CDPProtocolType802_2 && protlen != 3 && protlen != 8) { // invalid length 527 return nil, fmt.Errorf("Invalid Address Protocol length %d", protlen) 528 } 529 plen := make([]byte, 8) 530 copy(plen[8-protlen:], v[2:2+protlen]) 531 protocol := CDPAddressType(binary.BigEndian.Uint64(plen)) 532 v = v[2+protlen:] 533 addrlen := binary.BigEndian.Uint16(v[0:2]) 534 ab := v[2 : 2+addrlen] 535 if protocol == CDPAddressTypeIPV4 && addrlen == 4 { 536 addresses = append(addresses, net.IPv4(ab[0], ab[1], ab[2], ab[3])) 537 } else if protocol == CDPAddressTypeIPV6 && addrlen == 16 { 538 addresses = append(addresses, net.IP(ab)) 539 } else { 540 // only handle IPV4 & IPV6 for now 541 } 542 v = v[2+addrlen:] 543 if len(v) < 8 { 544 break 545 } 546 } 547 return 548 } 549 550 func (t CDPTLVType) String() (s string) { 551 switch t { 552 case CDPTLVDevID: 553 s = "Device ID" 554 case CDPTLVAddress: 555 s = "Addresses" 556 case CDPTLVPortID: 557 s = "Port ID" 558 case CDPTLVCapabilities: 559 s = "Capabilities" 560 case CDPTLVVersion: 561 s = "Software Version" 562 case CDPTLVPlatform: 563 s = "Platform" 564 case CDPTLVIPPrefix: 565 s = "IP Prefix" 566 case CDPTLVHello: 567 s = "Protocol Hello" 568 case CDPTLVVTPDomain: 569 s = "VTP Management Domain" 570 case CDPTLVNativeVLAN: 571 s = "Native VLAN" 572 case CDPTLVFullDuplex: 573 s = "Full Duplex" 574 case CDPTLVVLANReply: 575 s = "VoIP VLAN Reply" 576 case CDPTLVVLANQuery: 577 s = "VLANQuery" 578 case CDPTLVPower: 579 s = "Power consumption" 580 case CDPTLVMTU: 581 s = "MTU" 582 case CDPTLVExtendedTrust: 583 s = "Extended Trust Bitmap" 584 case CDPTLVUntrustedCOS: 585 s = "Untrusted Port CoS" 586 case CDPTLVSysName: 587 s = "System Name" 588 case CDPTLVSysOID: 589 s = "System OID" 590 case CDPTLVMgmtAddresses: 591 s = "Management Addresses" 592 case CDPTLVLocation: 593 s = "Location" 594 case CDPTLVExternalPortID: 595 s = "External Port ID" 596 case CDPTLVPowerRequested: 597 s = "Power Requested" 598 case CDPTLVPowerAvailable: 599 s = "Power Available" 600 case CDPTLVPortUnidirectional: 601 s = "Port Unidirectional" 602 case CDPTLVEnergyWise: 603 s = "Energy Wise" 604 case CDPTLVSparePairPOE: 605 s = "Spare Pair POE" 606 default: 607 s = "Unknown" 608 } 609 return 610 } 611 612 func (a CDPAddressType) String() (s string) { 613 switch a { 614 case CDPAddressTypeCLNP: 615 s = "Connectionless Network Protocol" 616 case CDPAddressTypeIPV4: 617 s = "IPv4" 618 case CDPAddressTypeIPV6: 619 s = "IPv6" 620 case CDPAddressTypeDECNET: 621 s = "DECnet Phase IV" 622 case CDPAddressTypeAPPLETALK: 623 s = "Apple Talk" 624 case CDPAddressTypeIPX: 625 s = "Novell IPX" 626 case CDPAddressTypeVINES: 627 s = "Banyan VINES" 628 case CDPAddressTypeXNS: 629 s = "Xerox Network Systems" 630 case CDPAddressTypeAPOLLO: 631 s = "Apollo" 632 default: 633 s = "Unknown" 634 } 635 return 636 } 637 638 func (t CDPEnergyWiseSubtype) String() (s string) { 639 switch t { 640 case CDPEnergyWiseRole: 641 s = "Role" 642 case CDPEnergyWiseDomain: 643 s = "Domain" 644 case CDPEnergyWiseName: 645 s = "Name" 646 case CDPEnergyWiseReplyTo: 647 s = "ReplyTo" 648 default: 649 s = "Unknown" 650 } 651 return 652 } 653 654 func checkCDPTLVLen(v CiscoDiscoveryValue, l int) (err error) { 655 if len(v.Value) < l { 656 err = fmt.Errorf("Invalid TLV %v length %d", v.Type, len(v.Value)) 657 } 658 return 659 }