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  }