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