cdp.go 19 KB

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