aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/google/gopacket/layers/ctp.go
blob: 82875845a728048e5a4bd1557e9180e5ad4c724f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// 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"
)

// EthernetCTPFunction is the function code used by the EthernetCTP protocol to identify each
// EthernetCTP layer.
type EthernetCTPFunction uint16

// EthernetCTPFunction values.
const (
	EthernetCTPFunctionReply       EthernetCTPFunction = 1
	EthernetCTPFunctionForwardData EthernetCTPFunction = 2
)

// EthernetCTP implements the EthernetCTP protocol, see http://www.mit.edu/people/jhawk/ctp.html.
// We split EthernetCTP up into the top-level EthernetCTP layer, followed by zero or more
// EthernetCTPForwardData layers, followed by a final EthernetCTPReply layer.
type EthernetCTP struct {
	BaseLayer
	SkipCount uint16
}

// LayerType returns gopacket.LayerTypeEthernetCTP.
func (c *EthernetCTP) LayerType() gopacket.LayerType {
	return LayerTypeEthernetCTP
}

// EthernetCTPForwardData is the ForwardData layer inside EthernetCTP.  See EthernetCTP's docs for more
// details.
type EthernetCTPForwardData struct {
	BaseLayer
	Function       EthernetCTPFunction
	ForwardAddress []byte
}

// LayerType returns gopacket.LayerTypeEthernetCTPForwardData.
func (c *EthernetCTPForwardData) LayerType() gopacket.LayerType {
	return LayerTypeEthernetCTPForwardData
}

// ForwardEndpoint returns the EthernetCTPForwardData ForwardAddress as an endpoint.
func (c *EthernetCTPForwardData) ForwardEndpoint() gopacket.Endpoint {
	return gopacket.NewEndpoint(EndpointMAC, c.ForwardAddress)
}

// EthernetCTPReply is the Reply layer inside EthernetCTP.  See EthernetCTP's docs for more details.
type EthernetCTPReply struct {
	BaseLayer
	Function      EthernetCTPFunction
	ReceiptNumber uint16
	Data          []byte
}

// LayerType returns gopacket.LayerTypeEthernetCTPReply.
func (c *EthernetCTPReply) LayerType() gopacket.LayerType {
	return LayerTypeEthernetCTPReply
}

// Payload returns the EthernetCTP reply's Data bytes.
func (c *EthernetCTPReply) Payload() []byte { return c.Data }

func decodeEthernetCTP(data []byte, p gopacket.PacketBuilder) error {
	c := &EthernetCTP{
		SkipCount: binary.LittleEndian.Uint16(data[:2]),
		BaseLayer: BaseLayer{data[:2], data[2:]},
	}
	if c.SkipCount%2 != 0 {
		return fmt.Errorf("EthernetCTP skip count is odd: %d", c.SkipCount)
	}
	p.AddLayer(c)
	return p.NextDecoder(gopacket.DecodeFunc(decodeEthernetCTPFromFunctionType))
}

// decodeEthernetCTPFromFunctionType reads in the first 2 bytes to determine the EthernetCTP
// layer type to decode next, then decodes based on that.
func decodeEthernetCTPFromFunctionType(data []byte, p gopacket.PacketBuilder) error {
	function := EthernetCTPFunction(binary.LittleEndian.Uint16(data[:2]))
	switch function {
	case EthernetCTPFunctionReply:
		reply := &EthernetCTPReply{
			Function:      function,
			ReceiptNumber: binary.LittleEndian.Uint16(data[2:4]),
			Data:          data[4:],
			BaseLayer:     BaseLayer{data, nil},
		}
		p.AddLayer(reply)
		p.SetApplicationLayer(reply)
		return nil
	case EthernetCTPFunctionForwardData:
		forward := &EthernetCTPForwardData{
			Function:       function,
			ForwardAddress: data[2:8],
			BaseLayer:      BaseLayer{data[:8], data[8:]},
		}
		p.AddLayer(forward)
		return p.NextDecoder(gopacket.DecodeFunc(decodeEthernetCTPFromFunctionType))
	}
	return fmt.Errorf("Unknown EthernetCTP function type %v", function)
}