123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- // Copyright 2012 Google, Inc. All rights reserved.
- // Copyright 2009-2011 Andreas Krennmair. 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"
- "github.com/google/gopacket"
- "net"
- )
- // EthernetBroadcast is the broadcast MAC address used by Ethernet.
- var EthernetBroadcast = net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
- // Ethernet is the layer for Ethernet frame headers.
- type Ethernet struct {
- BaseLayer
- SrcMAC, DstMAC net.HardwareAddr
- EthernetType EthernetType
- // Length is only set if a length field exists within this header. Ethernet
- // headers follow two different standards, one that uses an EthernetType, the
- // other which defines a length the follows with a LLC header (802.3). If the
- // former is the case, we set EthernetType and Length stays 0. In the latter
- // case, we set Length and EthernetType = EthernetTypeLLC.
- Length uint16
- }
- // LayerType returns LayerTypeEthernet
- func (e *Ethernet) LayerType() gopacket.LayerType { return LayerTypeEthernet }
- func (e *Ethernet) LinkFlow() gopacket.Flow {
- return gopacket.NewFlow(EndpointMAC, e.SrcMAC, e.DstMAC)
- }
- func (eth *Ethernet) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
- if len(data) < 14 {
- return errors.New("Ethernet packet too small")
- }
- eth.DstMAC = net.HardwareAddr(data[0:6])
- eth.SrcMAC = net.HardwareAddr(data[6:12])
- eth.EthernetType = EthernetType(binary.BigEndian.Uint16(data[12:14]))
- eth.BaseLayer = BaseLayer{data[:14], data[14:]}
- eth.Length = 0
- if eth.EthernetType < 0x0600 {
- eth.Length = uint16(eth.EthernetType)
- eth.EthernetType = EthernetTypeLLC
- if cmp := len(eth.Payload) - int(eth.Length); cmp < 0 {
- df.SetTruncated()
- } else if cmp > 0 {
- // Strip off bytes at the end, since we have too many bytes
- eth.Payload = eth.Payload[:len(eth.Payload)-cmp]
- }
- // fmt.Println(eth)
- }
- return nil
- }
- // SerializeTo writes the serialized form of this layer into the
- // SerializationBuffer, implementing gopacket.SerializableLayer.
- // See the docs for gopacket.SerializableLayer for more info.
- func (eth *Ethernet) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
- if len(eth.DstMAC) != 6 {
- return fmt.Errorf("invalid dst MAC: %v", eth.DstMAC)
- }
- if len(eth.SrcMAC) != 6 {
- return fmt.Errorf("invalid src MAC: %v", eth.SrcMAC)
- }
- payload := b.Bytes()
- bytes, err := b.PrependBytes(14)
- if err != nil {
- return err
- }
- copy(bytes, eth.DstMAC)
- copy(bytes[6:], eth.SrcMAC)
- if eth.Length != 0 || eth.EthernetType == EthernetTypeLLC {
- if opts.FixLengths {
- eth.Length = uint16(len(payload))
- }
- if eth.EthernetType != EthernetTypeLLC {
- return fmt.Errorf("ethernet type %v not compatible with length value %v", eth.EthernetType, eth.Length)
- } else if eth.Length > 0x0600 {
- return fmt.Errorf("invalid ethernet length %v", eth.Length)
- }
- binary.BigEndian.PutUint16(bytes[12:], eth.Length)
- } else {
- binary.BigEndian.PutUint16(bytes[12:], uint16(eth.EthernetType))
- }
- length := len(b.Bytes())
- if length < 60 {
- // Pad out to 60 bytes.
- padding, err := b.AppendBytes(60 - length)
- if err != nil {
- return err
- }
- copy(padding, lotsOfZeros[:])
- }
- return nil
- }
- func (eth *Ethernet) CanDecode() gopacket.LayerClass {
- return LayerTypeEthernet
- }
- func (eth *Ethernet) NextLayerType() gopacket.LayerType {
- return eth.EthernetType.LayerType()
- }
- func decodeEthernet(data []byte, p gopacket.PacketBuilder) error {
- eth := &Ethernet{}
- err := eth.DecodeFromBytes(data, p)
- if err != nil {
- return err
- }
- p.AddLayer(eth)
- p.SetLinkLayer(eth)
- return p.NextDecoder(eth.EthernetType)
- }
|