blob: 9a40e2d9124e348ac507dc9ac300c7028bcf7f0c [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301// 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 "bytes"
11 "encoding/binary"
12 "fmt"
13
14 "github.com/google/gopacket"
15)
16
17type PPPoEOpt uint16
18
19// Constants for PPPoE Options
20const (
21 PPPoEOptEndOfList PPPoEOpt = 0x0000
22 PPPoEOptServiceName PPPoEOpt = 0x0101
23 PPPoEOptAcName PPPoEOpt = 0x0102
24 PPPoEOptHostUniq PPPoEOpt = 0x0103
25 PPPoEOptAcCookie PPPoEOpt = 0x0104
26 PPPoEOptVendorSpecific PPPoEOpt = 0x0105
27 PPPoEOptRelaySessionId PPPoEOpt = 0x0110
28 PPPoEOptServiceErrorName PPPoEOpt = 0x0201
29 PPPoEOptAcSystemError PPPoEOpt = 0x0202
30 PPPoEOptGenericError PPPoEOpt = 0x0203
31)
32
33type PPPoEOption struct {
34 Type PPPoEOpt
35 Length uint16
36 Data []byte
37}
38
39func (o PPPoEOption) encode(b []byte) (uint16, error) {
40 binary.BigEndian.PutUint16(b[0:2], uint16(o.Type))
41 binary.BigEndian.PutUint16(b[2:4], uint16(o.Length))
42 copy(b[4:], o.Data)
43 return (4 + o.Length), nil
44}
45
46func (o PPPoEOption) decode(b []byte) error {
47 if len(b) < 4 {
48 return DecOptionNotEnoughData
49 }
50 o.Type = PPPoEOpt(binary.BigEndian.Uint16(b[0:2]))
51 o.Length = binary.BigEndian.Uint16(b[2:4])
52 if int(o.Length) > len(b[4:]) {
53 return DecOptionNotEnoughData
54 }
55 o.Data = b[4 : 4+int(o.Length)]
56 return nil
57}
58
59func NewPPPoEOption(opt PPPoEOpt, data []byte) PPPoEOption {
60 length := (uint16)(len(data))
61 option := PPPoEOption{Type: opt, Length: length, Data: data}
62 return option
63}
64
65func (o PPPoEOption) String() string {
66 return fmt.Sprintf("Option(%s:%v)", o.Type, o.Data)
67}
68
69func (o PPPoEOption) length() int {
70 return 4 + int(o.Length)
71}
72
73type PPPoEOptions []PPPoEOption
74
75// String returns a string version of the options list.
76func (o PPPoEOptions) String() string {
77 buf := &bytes.Buffer{}
78 buf.WriteByte('[')
79 for i, opt := range o {
80 buf.WriteString(opt.String())
81 if i+1 != len(o) {
82 buf.WriteString(", ")
83 }
84 }
85 buf.WriteByte(']')
86 return buf.String()
87}
88
89func (o PPPoEOptions) length() int {
90 length := 0
91 for _, op := range o {
92 length = length + op.length()
93 }
94 return length
95}
96
97// String returns a string version of a PPPoEOpt.
98func (o PPPoEOpt) String() string {
99 switch o {
100 case PPPoEOptEndOfList:
101 return "EndOfList"
102 case PPPoEOptServiceName:
103 return "ServiceName"
104 case PPPoEOptAcName:
105 return "AcName"
106 case PPPoEOptHostUniq:
107 return "HostUniq"
108 case PPPoEOptAcCookie:
109 return "AcCookie"
110 case PPPoEOptVendorSpecific:
111 return "VendorSpecific"
112 case PPPoEOptRelaySessionId:
113 return "RelaySessionId"
114 case PPPoEOptServiceErrorName:
115 return "ServiceErrorName"
116 case PPPoEOptAcSystemError:
117 return "AcSystemError"
118 case PPPoEOptGenericError:
119 return "GenericError"
120 default:
121 return "Unknown"
122 }
123}
124
125// PPPoE is the layer for PPPoE encapsulation headers.
126type PPPoE struct {
127 BaseLayer
128 Version uint8
129 Type uint8
130 Code PPPoECode
131 SessionId uint16
132 Length uint16
133 Options PPPoEOptions
134}
135
136// LayerType returns gopacket.LayerTypePPPoE.
137func (p *PPPoE) LayerType() gopacket.LayerType {
138 return LayerTypePPPoE
139}
140
141func (p *PPPoE) DecodeOptions(data []byte, len uint16) {
142
143 start := uint16(0)
144 stop := len
145 for start < stop {
146 pppoeOpt := &PPPoEOption{}
147 pppoeOpt.Type = PPPoEOpt(binary.BigEndian.Uint16(data[start : start+2]))
148 pppoeOpt.Length = binary.BigEndian.Uint16(data[start+2 : start+4])
149 if pppoeOpt.Length != 0 {
150 pppoeOpt.Data = data[start+4 : start+4+pppoeOpt.Length]
151 }
152 start = start + 4 + pppoeOpt.Length
153 p.Options = append(p.Options, *pppoeOpt)
154 }
155
156}
157
158// decodePPPoE decodes the PPPoE header (see http://tools.ietf.org/html/rfc2516).
159func decodePPPoE(data []byte, p gopacket.PacketBuilder) error {
160
161 pppoe := &PPPoE{
162 Version: data[0] >> 4,
163 Type: data[0] & 0x0F,
164 Code: PPPoECode(data[1]),
165 SessionId: binary.BigEndian.Uint16(data[2:4]),
166 Length: binary.BigEndian.Uint16(data[4:6]),
167 }
168 pppoe.DecodeOptions(data[6:], pppoe.Length)
169 pppoe.BaseLayer = BaseLayer{data[:6], data[6 : 6+pppoe.Length]}
170 p.AddLayer(pppoe)
171 return p.NextDecoder(pppoe.Code)
172}
173
174// SerializeTo writes the serialized form of this layer into the
175// SerializationBuffer, implementing gopacket.SerializableLayer.
176// See the docs for gopacket.SerializableLayer for more info.
177func (p *PPPoE) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
178 payload := b.Bytes()
179
180 //Pkt length with Options
181 length := 6
182 optLength := 0
183 for _, o := range p.Options {
184 optLength = optLength + o.length()
185 }
186
187 bytes, err := b.PrependBytes(length + optLength)
188 if err != nil {
189 return err
190 }
191 bytes[0] = (p.Version << 4) | p.Type
192 bytes[1] = byte(p.Code)
193 binary.BigEndian.PutUint16(bytes[2:], p.SessionId)
194 if opts.FixLengths {
195 p.Length = uint16(len(payload) + optLength)
196 }
197 binary.BigEndian.PutUint16(bytes[4:], p.Length)
198
199 //Encoding the options
200 start := uint16(6)
201 for _, option := range p.Options {
202 optLen, _ := option.encode(bytes[start:])
203 start = start + optLen
204 }
205 return nil
206}