blob: 0775ac0b6d4611c494ea6d191f3320098aa0d7e5 [file] [log] [blame]
// 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"
)
// Potential values for ARP.Operation.
const (
ARPRequest = 1
ARPReply = 2
)
// ARP is a ARP packet header.
type ARP struct {
BaseLayer
AddrType LinkType
Protocol EthernetType
HwAddressSize uint8
ProtAddressSize uint8
Operation uint16
SourceHwAddress []byte
SourceProtAddress []byte
DstHwAddress []byte
DstProtAddress []byte
}
// LayerType returns LayerTypeARP
func (arp *ARP) LayerType() gopacket.LayerType { return LayerTypeARP }
// DecodeFromBytes decodes the given bytes into this layer.
func (arp *ARP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 8 {
df.SetTruncated()
return fmt.Errorf("ARP length %d too short", len(data))
}
arp.AddrType = LinkType(binary.BigEndian.Uint16(data[0:2]))
arp.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4]))
arp.HwAddressSize = data[4]
arp.ProtAddressSize = data[5]
arp.Operation = binary.BigEndian.Uint16(data[6:8])
arpLength := 8 + 2*arp.HwAddressSize + 2*arp.ProtAddressSize
if len(data) < int(arpLength) {
df.SetTruncated()
return fmt.Errorf("ARP length %d too short, %d expected", len(data), arpLength)
}
arp.SourceHwAddress = data[8 : 8+arp.HwAddressSize]
arp.SourceProtAddress = data[8+arp.HwAddressSize : 8+arp.HwAddressSize+arp.ProtAddressSize]
arp.DstHwAddress = data[8+arp.HwAddressSize+arp.ProtAddressSize : 8+2*arp.HwAddressSize+arp.ProtAddressSize]
arp.DstProtAddress = data[8+2*arp.HwAddressSize+arp.ProtAddressSize : 8+2*arp.HwAddressSize+2*arp.ProtAddressSize]
arp.Contents = data[:arpLength]
arp.Payload = data[arpLength:]
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 (arp *ARP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
size := 8 + len(arp.SourceHwAddress) + len(arp.SourceProtAddress) + len(arp.DstHwAddress) + len(arp.DstProtAddress)
bytes, err := b.PrependBytes(size)
if err != nil {
return err
}
if opts.FixLengths {
if len(arp.SourceHwAddress) != len(arp.DstHwAddress) {
return errors.New("mismatched hardware address sizes")
}
arp.HwAddressSize = uint8(len(arp.SourceHwAddress))
if len(arp.SourceProtAddress) != len(arp.DstProtAddress) {
return errors.New("mismatched prot address sizes")
}
arp.ProtAddressSize = uint8(len(arp.SourceProtAddress))
}
binary.BigEndian.PutUint16(bytes, uint16(arp.AddrType))
binary.BigEndian.PutUint16(bytes[2:], uint16(arp.Protocol))
bytes[4] = arp.HwAddressSize
bytes[5] = arp.ProtAddressSize
binary.BigEndian.PutUint16(bytes[6:], arp.Operation)
start := 8
for _, addr := range [][]byte{
arp.SourceHwAddress,
arp.SourceProtAddress,
arp.DstHwAddress,
arp.DstProtAddress,
} {
copy(bytes[start:], addr)
start += len(addr)
}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (arp *ARP) CanDecode() gopacket.LayerClass {
return LayerTypeARP
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (arp *ARP) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func decodeARP(data []byte, p gopacket.PacketBuilder) error {
arp := &ARP{}
return decodingLayerDecoder(arp, data, p)
}