blob: 095f9261250629edd10c72a3fab7855ccb82ff04 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301// 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
12package layers
13
14import (
15 "encoding/binary"
16 "errors"
17 "fmt"
18 "net"
19
20 "github.com/google/gopacket"
21)
22
23// CDPTLVType is the type of each TLV value in a CiscoDiscovery packet.
24type CDPTLVType uint16
25
26// CDPTLVType values.
27const (
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.
58type 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
66type 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.
75type CDPCapability uint32
76
77// CDPCapability values.
78const (
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
91type 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.
104const (
105 CDPPoEFourWire byte = 0x01
106 CDPPoEPDArch byte = 0x02
107 CDPPoEPDRequest byte = 0x04
108 CDPPoEPSE byte = 0x08
109)
110
111// CDPSparePairPoE provides information on PoE.
112type 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
120type CDPVLANDialogue struct {
121 ID uint8
122 VLAN uint16
123}
124
125// CDPPowerDialogue encapsulates a Power Query/Reply
126type CDPPowerDialogue struct {
127 ID uint16
128 MgmtID uint16
129 Values []uint32
130}
131
132// CDPLocation provides location information for a CDP device.
133type CDPLocation struct {
134 Type uint8 // Undocumented
135 Location string
136}
137
138// CDPHello is a Cisco Hello message (undocumented, hence the "Unknown" fields)
139type 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.
155type CDPEnergyWiseSubtype uint32
156
157// CDPEnergyWiseSubtype values.
158const (
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.
166type 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
186type 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.
217func (c *CiscoDiscovery) LayerType() gopacket.LayerType {
218 return LayerTypeCiscoDiscovery
219}
220
221func 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.
242func (c *CiscoDiscoveryInfo) LayerType() gopacket.LayerType {
243 return LayerTypeCiscoDiscoveryInfo
244}
245
246func 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
270func 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
489const (
490 CDPProtocolTypeNLPID byte = 1
491 CDPProtocolType802_2 byte = 2
492)
493
494// CDPAddressType is used to define TLV values within CDP addresses.
495type CDPAddressType uint64
496
497// CDP Address types.
498const (
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
510func 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
550func (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
612func (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
638func (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
654func 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}