blob: 181db7d0e8c8cffcd7694ed81e9b065691a66384 [file] [log] [blame]
Gustavo Silva2bcc8052021-01-22 13:48:30 -03001/*
2 * Copyright 2021-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onlab.packet;
17
18import java.nio.ByteBuffer;
19import java.util.ArrayList;
20import java.util.List;
21import java.util.stream.Stream;
22
23import static org.onlab.packet.PacketUtils.checkInput;
24
25public class PPPoED extends BasePacket {
26 protected byte version;
27 protected byte type;
28 protected byte code;
29 protected short sessionId;
30 protected short payloadLength;
31 protected List<PPPoEDTag> tags = new ArrayList<>();
32
33 // PPPoED packet types
34 public static final byte PPPOED_CODE_PADI = (byte) 0x09;
35 public static final byte PPPOED_CODE_PADO = (byte) 0x07;
36 public static final byte PPPOED_CODE_PADR = (byte) 0x19;
37 public static final byte PPPOED_CODE_PADS = (byte) 0x65;
38 public static final byte PPPOED_CODE_PADT = (byte) 0xa7;
39
40 private static final int HEADER_LENGTH = 6;
41 private static final int TAG_HEADER_LENGTH = 4;
42
43 public PPPoED() {
44 }
45
46 public byte getVersion() {
47 return version;
48 }
49
50 public void setVersion(byte version) {
51 this.version = version;
52 }
53
54 public byte getType() {
55 return type;
56 }
57
58 public void setType(byte type) {
59 this.type = type;
60 }
61
62 public byte getCode() {
63 return code;
64 }
65
66 public void setCode(byte code) {
67 this.code = code;
68 }
69
70 public short getSessionId() {
71 return sessionId;
72 }
73
74 public void setSessionId(short sessionId) {
75 this.sessionId = sessionId;
76 }
77
78 public short getPayloadLength() {
79 return payloadLength;
80 }
81
82 public void setPayloadLength(short payloadLength) {
83 this.payloadLength = payloadLength;
84 }
85
86 public List<PPPoEDTag> getTags() {
87 return tags;
88 }
89
90 public void setTags(List<PPPoEDTag> tags) {
91 this.tags = tags;
92 }
93
94 /**
95 * Gets a list of tags from the packet.
96 *
97 * @param tagType the type field of the required tags
98 * @return List of the tags that match the type or an empty list if there is none
99 */
100 public ArrayList<PPPoEDTag> getTagList(short tagType) {
101 ArrayList<PPPoEDTag> tagList = new ArrayList<>();
102 for (int i = 0; i < this.tags.size(); i++) {
103 if (this.tags.get(i).getType() == tagType) {
104 tagList.add(this.tags.get(i));
105 }
106 }
107 return tagList;
108 }
109
110 /**
111 * Gets a tag from the packet.
112 *
113 * @param tagType the type field of the required tag
114 * @return the first tag that matches the type or null if does not exist
115 */
116 public PPPoEDTag getTag(short tagType) {
117 for (int i = 0; i < this.tags.size(); i++) {
118 if (this.tags.get(i).getType() == tagType) {
119 return this.tags.get(i);
120 }
121 }
122 return null;
123 }
124
125 /**
126 * Sets a tag in the packet.
127 *
128 * @param tagType the type field of the tag to set
129 * @param value value to be set
130 * @return reference to the tag object
131 */
132 public PPPoEDTag setTag(short tagType, byte[] value) {
133 short tagLength = (short) (value.length);
134 PPPoEDTag newTag = new PPPoEDTag(tagType, tagLength, value);
135 this.tags.add(newTag);
136 this.payloadLength += TAG_HEADER_LENGTH + tagLength;
137 return newTag;
138 }
139
140 /**
141 * Deserializer for PPPoED packets.
142 *
143 * @return deserializer
144 */
145 public static Deserializer<PPPoED> deserializer() {
146 return (data, offset, length) -> {
147 checkInput(data, offset, length, HEADER_LENGTH);
148
149 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
150 PPPoED pppoed = new PPPoED();
151 byte versionByte = bb.get();
152 pppoed.setVersion((byte) (versionByte >> 4 & 0xf));
153 pppoed.setType((byte) (versionByte & 0xf));
154 pppoed.setCode(bb.get());
155 pppoed.setSessionId(bb.getShort());
156 pppoed.setPayloadLength(bb.getShort());
157 int remainingLength = pppoed.payloadLength;
158 while (remainingLength > 0 && bb.hasRemaining()) {
159 PPPoEDTag tag = new PPPoEDTag();
160 tag.setType(bb.getShort());
161 tag.setLength(bb.getShort());
162 tag.value = new byte[tag.length];
163 bb.get(tag.value, 0, tag.length);
164 pppoed.tags.add(tag);
165 remainingLength -= tag.length + TAG_HEADER_LENGTH;
166 }
167 return pppoed;
168 };
169 }
170
171 @Override
172 public byte[] serialize() {
173 final byte[] data = new byte[this.payloadLength + HEADER_LENGTH];
174 final ByteBuffer bb = ByteBuffer.wrap(data);
175 bb.put((byte) ((this.version & 0xf) << 4 | this.type & 0xf));
176 bb.put(this.code);
177 bb.putShort(this.sessionId);
178 bb.putShort(this.payloadLength);
179 for (int i = 0; i < this.tags.size(); i++) {
180 PPPoEDTag tag = this.tags.get(i);
181 bb.putShort(tag.getType());
182 bb.putShort(tag.getLength());
183 bb.put(tag.getValue());
184 }
185 return data;
186 }
187
188 @Override
189 public String toString() {
190 return "PPPoED{" +
191 "version=" + version +
192 ", type=" + type +
193 ", code=" + code +
194 ", session_id=" + sessionId +
195 ", payload_length=" + payloadLength +
196 ", tags=" + tags +
197 '}';
198 }
199
200 public enum Type {
201 PADI(PPPOED_CODE_PADI),
202 PADO(PPPOED_CODE_PADO),
203 PADR(PPPOED_CODE_PADR),
204 PADS(PPPOED_CODE_PADS),
205 PADT(PPPOED_CODE_PADT);
206
207 public int value;
208
209 Type(int value) {
210 this.value = value;
211 }
212
213 public static Type getTypeByValue(int value) {
214 return Stream.of(values())
215 .filter(el -> el.value == value)
216 .findFirst()
217 .orElse(null);
218 }
219 }
220}