cdp.go 19 KB

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