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