blob: 31c2a6ea16d3a1ab03d41bbb1728466249eb5dc6 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301// 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
7package layers
8
9import (
10 "encoding/binary"
11 "errors"
12 "fmt"
13 "net"
14
15 "github.com/google/gopacket"
16)
17
18type 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.
25type 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.
41func (s *STP) LayerType() gopacket.LayerType { return LayerTypeSTP }
42
43// CanDecode returns the set of layer types that this DecodingLayer can decode.
44func (s *STP) CanDecode() gopacket.LayerClass {
45 return LayerTypeSTP
46}
47
48// DecodeFromBytes decodes the given bytes into this layer.
49func (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.
80func (stp *STP) NextLayerType() gopacket.LayerType {
81 return gopacket.LayerTypePayload
82}
83
84// Check if the priority value is correct.
85func 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.
99func (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
147func decodeSTP(data []byte, p gopacket.PacketBuilder) error {
148 stp := &STP{}
149 return decodingLayerDecoder(stp, data, p)
150}