Fix unit tests
[govpp.git] / vendor / github.com / google / gopacket / layers / cdp.go
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         "fmt"
17         "net"
18
19         "github.com/google/gopacket"
20 )
21
22 // CDPTLVType is the type of each TLV value in a CiscoDiscovery packet.
23 type CDPTLVType uint16
24
25 // CDPTLVType values.
26 const (
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.
57 type 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
65 type 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.
74 type CDPCapability uint32
75
76 // CDPCapability values.
77 const (
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
90 type 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.
103 const (
104         CDPPoEFourWire  byte = 0x01
105         CDPPoEPDArch    byte = 0x02
106         CDPPoEPDRequest byte = 0x04
107         CDPPoEPSE       byte = 0x08
108 )
109
110 // CDPSparePairPoE provides information on PoE.
111 type 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
119 type CDPVLANDialogue struct {
120         ID   uint8
121         VLAN uint16
122 }
123
124 // CDPPowerDialogue encapsulates a Power Query/Reply
125 type CDPPowerDialogue struct {
126         ID     uint16
127         MgmtID uint16
128         Values []uint32
129 }
130
131 // CDPLocation provides location information for a CDP device.
132 type CDPLocation struct {
133         Type     uint8 // Undocumented
134         Location string
135 }
136
137 // CDPHello is a Cisco Hello message (undocumented, hence the "Unknown" fields)
138 type 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.
154 type CDPEnergyWiseSubtype uint32
155
156 // CDPEnergyWiseSubtype values.
157 const (
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.
165 type 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
185 type 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.
216 func (c *CiscoDiscovery) LayerType() gopacket.LayerType {
217         return LayerTypeCiscoDiscovery
218 }
219
220 func 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.
241 func (c *CiscoDiscoveryInfo) LayerType() gopacket.LayerType {
242         return LayerTypeCiscoDiscoveryInfo
243 }
244
245 func 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
262 func 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
481 const (
482         CDPProtocolTypeNLPID byte = 1
483         CDPProtocolType802_2 byte = 2
484 )
485
486 // CDPAddressType is used to define TLV values within CDP addresses.
487 type CDPAddressType uint64
488
489 // CDP Address types.
490 const (
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
502 func 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
542 func (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
604 func (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
630 func (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
646 func 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 }