github.com/gopacket/gopacket@v1.1.0/layers/stp.go (about) 1 // Copyright 2017 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 package layers 8 9 import ( 10 "encoding/binary" 11 "errors" 12 "fmt" 13 "net" 14 15 "github.com/gopacket/gopacket" 16 ) 17 18 type STPSwitchID struct { 19 Priority uint16 // Bridge priority 20 SysID uint16 // VLAN ID 21 HwAddr net.HardwareAddr 22 } 23 24 // STP decode spanning tree protocol packets to transport BPDU (bridge protocol data unit) message. 25 type STP struct { 26 BaseLayer 27 ProtocolID uint16 28 Version uint8 29 Type uint8 30 TC, TCA bool // TC: Topologie change ; TCA: Topologie change ack 31 RouteID, BridgeID STPSwitchID 32 Cost uint32 33 PortID uint16 34 MessageAge uint16 35 MaxAge uint16 36 HelloTime uint16 37 FDelay uint16 38 } 39 40 // LayerType returns gopacket.LayerTypeSTP. 41 func (s *STP) LayerType() gopacket.LayerType { return LayerTypeSTP } 42 43 // CanDecode returns the set of layer types that this DecodingLayer can decode. 44 func (s *STP) CanDecode() gopacket.LayerClass { 45 return LayerTypeSTP 46 } 47 48 // DecodeFromBytes decodes the given bytes into this layer. 49 func (stp *STP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { 50 stpLength := 35 51 if len(data) < stpLength { 52 df.SetTruncated() 53 return fmt.Errorf("STP length %d too short", len(data)) 54 } 55 56 stp.ProtocolID = binary.BigEndian.Uint16(data[:2]) 57 stp.Version = uint8(data[2]) 58 stp.Type = uint8(data[3]) 59 stp.TC = data[4]&0x01 != 0 60 stp.TCA = data[4]&0x80 != 0 61 stp.RouteID.Priority = binary.BigEndian.Uint16(data[5:7]) & 0xf000 62 stp.RouteID.SysID = binary.BigEndian.Uint16(data[5:7]) & 0x0fff 63 stp.RouteID.HwAddr = net.HardwareAddr(data[7:13]) 64 stp.Cost = binary.BigEndian.Uint32(data[13:17]) 65 stp.BridgeID.Priority = binary.BigEndian.Uint16(data[17:19]) & 0xf000 66 stp.BridgeID.SysID = binary.BigEndian.Uint16(data[17:19]) & 0x0fff 67 stp.BridgeID.HwAddr = net.HardwareAddr(data[19:25]) 68 stp.PortID = binary.BigEndian.Uint16(data[25:27]) 69 stp.MessageAge = binary.BigEndian.Uint16(data[27:29]) 70 stp.MaxAge = binary.BigEndian.Uint16(data[29:31]) 71 stp.HelloTime = binary.BigEndian.Uint16(data[31:33]) 72 stp.FDelay = binary.BigEndian.Uint16(data[33:35]) 73 stp.Contents = data[:stpLength] 74 stp.Payload = data[stpLength:] 75 76 return nil 77 } 78 79 // NextLayerType returns the layer type contained by this DecodingLayer. 80 func (stp *STP) NextLayerType() gopacket.LayerType { 81 return gopacket.LayerTypePayload 82 } 83 84 // Check if the priority value is correct. 85 func checkPriority(prio uint16) (uint16, error) { 86 if prio == 0 { 87 return prio, errors.New("Invalid Priority value must be in the rage <4096-61440> with an increment of 4096") 88 } 89 if prio%4096 == 0 { 90 return prio, nil 91 } else { 92 return prio, errors.New("Invalid Priority value must be in the rage <4096-61440> with an increment of 4096") 93 } 94 } 95 96 // SerializeTo writes the serialized form of this layer into the 97 // SerializationBuffer, implementing gopacket.SerializableLayer. 98 // See the docs for gopacket.SerializableLayer for more info. 99 func (s *STP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { 100 var flags uint8 = 0x00 101 bytes, err := b.PrependBytes(35) 102 if err != nil { 103 return err 104 } 105 binary.BigEndian.PutUint16(bytes, s.ProtocolID) 106 bytes[2] = s.Version 107 bytes[3] = s.Type 108 if s.TC { 109 flags |= 0x01 110 } 111 if s.TCA { 112 flags |= 0x80 113 } 114 bytes[4] = flags 115 116 prioRoot, err := checkPriority(s.RouteID.Priority) 117 if err != nil { 118 panic(err) 119 } 120 if s.RouteID.SysID >= 4096 { 121 panic("Invalid VlanID value ..!") 122 } 123 binary.BigEndian.PutUint16(bytes[5:7], prioRoot|s.RouteID.SysID) 124 copy(bytes[7:13], s.RouteID.HwAddr) 125 126 binary.BigEndian.PutUint32(bytes[13:17], s.Cost) 127 128 prioBridge, err := checkPriority(s.BridgeID.Priority) 129 if err != nil { 130 panic(err) 131 } 132 if s.BridgeID.SysID >= 4096 { 133 panic("Invalid VlanID value ..!") 134 } 135 binary.BigEndian.PutUint16(bytes[17:19], prioBridge|s.BridgeID.SysID) 136 copy(bytes[19:25], s.BridgeID.HwAddr) 137 138 binary.BigEndian.PutUint16(bytes[25:27], s.PortID) 139 binary.BigEndian.PutUint16(bytes[27:29], s.MessageAge) 140 binary.BigEndian.PutUint16(bytes[29:31], s.MaxAge) 141 binary.BigEndian.PutUint16(bytes[31:33], s.HelloTime) 142 binary.BigEndian.PutUint16(bytes[33:35], s.FDelay) 143 144 return nil 145 } 146 147 func decodeSTP(data []byte, p gopacket.PacketBuilder) error { 148 stp := &STP{} 149 return decodingLayerDecoder(stp, data, p) 150 }