1// Copyright 2012 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	"fmt"
12	"github.com/google/gopacket"
13)
14
15type RUDP struct {
16	BaseLayer
17	SYN, ACK, EACK, RST, NUL bool
18	Version                  uint8
19	HeaderLength             uint8
20	SrcPort, DstPort         RUDPPort
21	DataLength               uint16
22	Seq, Ack, Checksum       uint32
23	VariableHeaderArea       []byte
24	// RUDPHeaderSyn contains SYN information for the RUDP packet,
25	// if the SYN flag is set
26	*RUDPHeaderSYN
27	// RUDPHeaderEack contains EACK information for the RUDP packet,
28	// if the EACK flag is set.
29	*RUDPHeaderEACK
30}
31
32type RUDPHeaderSYN struct {
33	MaxOutstandingSegments, MaxSegmentSize, OptionFlags uint16
34}
35
36type RUDPHeaderEACK struct {
37	SeqsReceivedOK []uint32
38}
39
40// LayerType returns gopacket.LayerTypeRUDP.
41func (r *RUDP) LayerType() gopacket.LayerType { return LayerTypeRUDP }
42
43func decodeRUDP(data []byte, p gopacket.PacketBuilder) error {
44	r := &RUDP{
45		SYN:          data[0]&0x80 != 0,
46		ACK:          data[0]&0x40 != 0,
47		EACK:         data[0]&0x20 != 0,
48		RST:          data[0]&0x10 != 0,
49		NUL:          data[0]&0x08 != 0,
50		Version:      data[0] & 0x3,
51		HeaderLength: data[1],
52		SrcPort:      RUDPPort(data[2]),
53		DstPort:      RUDPPort(data[3]),
54		DataLength:   binary.BigEndian.Uint16(data[4:6]),
55		Seq:          binary.BigEndian.Uint32(data[6:10]),
56		Ack:          binary.BigEndian.Uint32(data[10:14]),
57		Checksum:     binary.BigEndian.Uint32(data[14:18]),
58	}
59	if r.HeaderLength < 9 {
60		return fmt.Errorf("RUDP packet with too-short header length %d", r.HeaderLength)
61	}
62	hlen := int(r.HeaderLength) * 2
63	r.Contents = data[:hlen]
64	r.Payload = data[hlen : hlen+int(r.DataLength)]
65	r.VariableHeaderArea = data[18:hlen]
66	headerData := r.VariableHeaderArea
67	switch {
68	case r.SYN:
69		if len(headerData) != 6 {
70			return fmt.Errorf("RUDP packet invalid SYN header length: %d", len(headerData))
71		}
72		r.RUDPHeaderSYN = &RUDPHeaderSYN{
73			MaxOutstandingSegments: binary.BigEndian.Uint16(headerData[:2]),
74			MaxSegmentSize:         binary.BigEndian.Uint16(headerData[2:4]),
75			OptionFlags:            binary.BigEndian.Uint16(headerData[4:6]),
76		}
77	case r.EACK:
78		if len(headerData)%4 != 0 {
79			return fmt.Errorf("RUDP packet invalid EACK header length: %d", len(headerData))
80		}
81		r.RUDPHeaderEACK = &RUDPHeaderEACK{make([]uint32, len(headerData)/4)}
82		for i := 0; i < len(headerData); i += 4 {
83			r.SeqsReceivedOK[i/4] = binary.BigEndian.Uint32(headerData[i : i+4])
84		}
85	}
86	p.AddLayer(r)
87	p.SetTransportLayer(r)
88	return p.NextDecoder(gopacket.LayerTypePayload)
89}
90
91func (r *RUDP) TransportFlow() gopacket.Flow {
92	return gopacket.NewFlow(EndpointRUDPPort, []byte{byte(r.SrcPort)}, []byte{byte(r.DstPort)})
93}
94