blob: 8435129b947fb9f584a3e920d6cb857dce7dfa8f [file] [log] [blame]
// Copyright 2012 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"
"fmt"
"github.com/google/gopacket"
)
type RUDP struct {
BaseLayer
SYN, ACK, EACK, RST, NUL bool
Version uint8
HeaderLength uint8
SrcPort, DstPort RUDPPort
DataLength uint16
Seq, Ack, Checksum uint32
VariableHeaderArea []byte
// RUDPHeaderSyn contains SYN information for the RUDP packet,
// if the SYN flag is set
*RUDPHeaderSYN
// RUDPHeaderEack contains EACK information for the RUDP packet,
// if the EACK flag is set.
*RUDPHeaderEACK
}
type RUDPHeaderSYN struct {
MaxOutstandingSegments, MaxSegmentSize, OptionFlags uint16
}
type RUDPHeaderEACK struct {
SeqsReceivedOK []uint32
}
// LayerType returns gopacket.LayerTypeRUDP.
func (r *RUDP) LayerType() gopacket.LayerType { return LayerTypeRUDP }
func decodeRUDP(data []byte, p gopacket.PacketBuilder) error {
r := &RUDP{
SYN: data[0]&0x80 != 0,
ACK: data[0]&0x40 != 0,
EACK: data[0]&0x20 != 0,
RST: data[0]&0x10 != 0,
NUL: data[0]&0x08 != 0,
Version: data[0] & 0x3,
HeaderLength: data[1],
SrcPort: RUDPPort(data[2]),
DstPort: RUDPPort(data[3]),
DataLength: binary.BigEndian.Uint16(data[4:6]),
Seq: binary.BigEndian.Uint32(data[6:10]),
Ack: binary.BigEndian.Uint32(data[10:14]),
Checksum: binary.BigEndian.Uint32(data[14:18]),
}
if r.HeaderLength < 9 {
return fmt.Errorf("RUDP packet with too-short header length %d", r.HeaderLength)
}
hlen := int(r.HeaderLength) * 2
r.Contents = data[:hlen]
r.Payload = data[hlen : hlen+int(r.DataLength)]
r.VariableHeaderArea = data[18:hlen]
headerData := r.VariableHeaderArea
switch {
case r.SYN:
if len(headerData) != 6 {
return fmt.Errorf("RUDP packet invalid SYN header length: %d", len(headerData))
}
r.RUDPHeaderSYN = &RUDPHeaderSYN{
MaxOutstandingSegments: binary.BigEndian.Uint16(headerData[:2]),
MaxSegmentSize: binary.BigEndian.Uint16(headerData[2:4]),
OptionFlags: binary.BigEndian.Uint16(headerData[4:6]),
}
case r.EACK:
if len(headerData)%4 != 0 {
return fmt.Errorf("RUDP packet invalid EACK header length: %d", len(headerData))
}
r.RUDPHeaderEACK = &RUDPHeaderEACK{make([]uint32, len(headerData)/4)}
for i := 0; i < len(headerData); i += 4 {
r.SeqsReceivedOK[i/4] = binary.BigEndian.Uint32(headerData[i : i+4])
}
}
p.AddLayer(r)
p.SetTransportLayer(r)
return p.NextDecoder(gopacket.LayerTypePayload)
}
func (r *RUDP) TransportFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointRUDPPort, []byte{byte(r.SrcPort)}, []byte{byte(r.DstPort)})
}