blob: 80584ba9f54c16d60941f818d47bc76f71b73b49 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
alshabibc4901cd2014-09-05 16:50:40 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
alshabibc4901cd2014-09-05 16:50:40 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
16
alshabibc4901cd2014-09-05 16:50:40 -070017package org.onlab.packet;
18
19import java.nio.ByteBuffer;
20import java.util.Arrays;
21
Jian Li5fc14292015-12-04 11:30:46 -080022import static com.google.common.base.MoreObjects.toStringHelper;
23import static org.onlab.packet.PacketUtils.checkHeaderLength;
24import static org.onlab.packet.PacketUtils.checkInput;
Jonathan Hart2a655752015-04-07 16:46:33 -070025
alshabibc4901cd2014-09-05 16:50:40 -070026/**
Jian Li5fc14292015-12-04 11:30:46 -080027 * Representation of an ARP Packet.
alshabibc4901cd2014-09-05 16:50:40 -070028 */
29public class ARP extends BasePacket {
30 public static final short HW_TYPE_ETHERNET = 0x1;
31
32 public static final short PROTO_TYPE_IP = 0x800;
33
34 public static final short OP_REQUEST = 0x1;
35 public static final short OP_REPLY = 0x2;
36 public static final short OP_RARP_REQUEST = 0x3;
37 public static final short OP_RARP_REPLY = 0x4;
38
Jonathan Hart2a655752015-04-07 16:46:33 -070039 public static final short INITIAL_HEADER_LENGTH = 8;
40
alshabibc4901cd2014-09-05 16:50:40 -070041 protected short hardwareType;
42 protected short protocolType;
43 protected byte hardwareAddressLength;
44 protected byte protocolAddressLength;
45 protected short opCode;
46 protected byte[] senderHardwareAddress;
47 protected byte[] senderProtocolAddress;
48 protected byte[] targetHardwareAddress;
49 protected byte[] targetProtocolAddress;
50
51 /**
52 * @return the hardwareType
53 */
54 public short getHardwareType() {
55 return this.hardwareType;
56 }
57
58 /**
tom5f18cf32014-09-13 14:10:57 -070059 * @param hwType
alshabibc4901cd2014-09-05 16:50:40 -070060 * the hardwareType to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -080061 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070062 */
63 public ARP setHardwareType(final short hwType) {
64 this.hardwareType = hwType;
65 return this;
66 }
67
68 /**
69 * @return the protocolType
70 */
71 public short getProtocolType() {
72 return this.protocolType;
73 }
74
75 /**
tom5f18cf32014-09-13 14:10:57 -070076 * @param protoType
alshabibc4901cd2014-09-05 16:50:40 -070077 * the protocolType to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -080078 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070079 */
80 public ARP setProtocolType(final short protoType) {
81 this.protocolType = protoType;
82 return this;
83 }
84
85 /**
86 * @return the hardwareAddressLength
87 */
88 public byte getHardwareAddressLength() {
89 return this.hardwareAddressLength;
90 }
91
92 /**
93 * @param hwAddressLength
94 * the hardwareAddressLength to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -080095 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070096 */
97 public ARP setHardwareAddressLength(final byte hwAddressLength) {
98 this.hardwareAddressLength = hwAddressLength;
99 return this;
100 }
101
102 /**
103 * @return the protocolAddressLength
104 */
105 public byte getProtocolAddressLength() {
106 return this.protocolAddressLength;
107 }
108
109 /**
tom5f18cf32014-09-13 14:10:57 -0700110 * @param protoAddressLength
alshabibc4901cd2014-09-05 16:50:40 -0700111 * the protocolAddressLength to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800112 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700113 */
114 public ARP setProtocolAddressLength(final byte protoAddressLength) {
115 this.protocolAddressLength = protoAddressLength;
116 return this;
117 }
118
119 /**
120 * @return the opCode
121 */
122 public short getOpCode() {
123 return this.opCode;
124 }
125
126 /**
tom5f18cf32014-09-13 14:10:57 -0700127 * @param op
alshabibc4901cd2014-09-05 16:50:40 -0700128 * the opCode to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800129 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700130 */
131 public ARP setOpCode(final short op) {
132 this.opCode = op;
133 return this;
134 }
135
136 /**
137 * @return the senderHardwareAddress
138 */
139 public byte[] getSenderHardwareAddress() {
140 return this.senderHardwareAddress;
141 }
142
143 /**
tom5f18cf32014-09-13 14:10:57 -0700144 * @param senderHWAddress
alshabibc4901cd2014-09-05 16:50:40 -0700145 * the senderHardwareAddress to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800146 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700147 */
148 public ARP setSenderHardwareAddress(final byte[] senderHWAddress) {
149 this.senderHardwareAddress = senderHWAddress;
150 return this;
151 }
152
153 /**
154 * @return the senderProtocolAddress
155 */
156 public byte[] getSenderProtocolAddress() {
157 return this.senderProtocolAddress;
158 }
159
160 /**
tom5f18cf32014-09-13 14:10:57 -0700161 * @param senderProtoAddress
alshabibc4901cd2014-09-05 16:50:40 -0700162 * the senderProtocolAddress to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800163 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700164 */
165 public ARP setSenderProtocolAddress(final byte[] senderProtoAddress) {
166 this.senderProtocolAddress = senderProtoAddress;
167 return this;
168 }
169
170 public ARP setSenderProtocolAddress(final int address) {
171 this.senderProtocolAddress = ByteBuffer.allocate(4).putInt(address)
172 .array();
173 return this;
174 }
175
176 /**
177 * @return the targetHardwareAddress
178 */
179 public byte[] getTargetHardwareAddress() {
180 return this.targetHardwareAddress;
181 }
182
183 /**
tom5f18cf32014-09-13 14:10:57 -0700184 * @param targetHWAddress
alshabibc4901cd2014-09-05 16:50:40 -0700185 * the targetHardwareAddress to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800186 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700187 */
188 public ARP setTargetHardwareAddress(final byte[] targetHWAddress) {
189 this.targetHardwareAddress = targetHWAddress;
190 return this;
191 }
192
193 /**
194 * @return the targetProtocolAddress
195 */
196 public byte[] getTargetProtocolAddress() {
197 return this.targetProtocolAddress;
198 }
199
200 /**
201 * @return True if gratuitous ARP (SPA = TPA), false otherwise
202 */
203 public boolean isGratuitous() {
204 assert this.senderProtocolAddress.length == this.targetProtocolAddress.length;
205
206 int indx = 0;
207 while (indx < this.senderProtocolAddress.length) {
208 if (this.senderProtocolAddress[indx] != this.targetProtocolAddress[indx]) {
209 return false;
210 }
211 indx++;
212 }
213
214 return true;
215 }
216
217 /**
tom5f18cf32014-09-13 14:10:57 -0700218 * @param targetProtoAddress
alshabibc4901cd2014-09-05 16:50:40 -0700219 * the targetProtocolAddress to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800220 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700221 */
222 public ARP setTargetProtocolAddress(final byte[] targetProtoAddress) {
223 this.targetProtocolAddress = targetProtoAddress;
224 return this;
225 }
226
227 public ARP setTargetProtocolAddress(final int address) {
228 this.targetProtocolAddress = ByteBuffer.allocate(4).putInt(address)
229 .array();
230 return this;
231 }
232
233 @Override
234 public byte[] serialize() {
235 final int length = 8 + 2 * (0xff & this.hardwareAddressLength) + 2
236 * (0xff & this.protocolAddressLength);
237 final byte[] data = new byte[length];
238 final ByteBuffer bb = ByteBuffer.wrap(data);
239 bb.putShort(this.hardwareType);
240 bb.putShort(this.protocolType);
241 bb.put(this.hardwareAddressLength);
242 bb.put(this.protocolAddressLength);
243 bb.putShort(this.opCode);
244 bb.put(this.senderHardwareAddress, 0, 0xff & this.hardwareAddressLength);
245 bb.put(this.senderProtocolAddress, 0, 0xff & this.protocolAddressLength);
246 bb.put(this.targetHardwareAddress, 0, 0xff & this.hardwareAddressLength);
247 bb.put(this.targetProtocolAddress, 0, 0xff & this.protocolAddressLength);
248 return data;
249 }
250
251 @Override
252 public IPacket deserialize(final byte[] data, final int offset,
Jonathan Hart2a655752015-04-07 16:46:33 -0700253 final int length) {
alshabibc4901cd2014-09-05 16:50:40 -0700254 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
255 this.hardwareType = bb.getShort();
256 this.protocolType = bb.getShort();
257 this.hardwareAddressLength = bb.get();
258 this.protocolAddressLength = bb.get();
259 this.opCode = bb.getShort();
260 this.senderHardwareAddress = new byte[0xff & this.hardwareAddressLength];
261 bb.get(this.senderHardwareAddress, 0, this.senderHardwareAddress.length);
262 this.senderProtocolAddress = new byte[0xff & this.protocolAddressLength];
263 bb.get(this.senderProtocolAddress, 0, this.senderProtocolAddress.length);
264 this.targetHardwareAddress = new byte[0xff & this.hardwareAddressLength];
265 bb.get(this.targetHardwareAddress, 0, this.targetHardwareAddress.length);
266 this.targetProtocolAddress = new byte[0xff & this.protocolAddressLength];
267 bb.get(this.targetProtocolAddress, 0, this.targetProtocolAddress.length);
268 return this;
269 }
270
271 /*
272 * (non-Javadoc)
273 *
274 * @see java.lang.Object#hashCode()
275 */
276 @Override
277 public int hashCode() {
278 final int prime = 13121;
279 int result = super.hashCode();
280 result = prime * result + this.hardwareAddressLength;
281 result = prime * result + this.hardwareType;
282 result = prime * result + this.opCode;
283 result = prime * result + this.protocolAddressLength;
284 result = prime * result + this.protocolType;
285 result = prime * result + Arrays.hashCode(this.senderHardwareAddress);
286 result = prime * result + Arrays.hashCode(this.senderProtocolAddress);
287 result = prime * result + Arrays.hashCode(this.targetHardwareAddress);
288 result = prime * result + Arrays.hashCode(this.targetProtocolAddress);
289 return result;
290 }
291
292 /*
293 * (non-Javadoc)
294 *
295 * @see java.lang.Object#equals(java.lang.Object)
296 */
297 @Override
298 public boolean equals(final Object obj) {
299 if (this == obj) {
300 return true;
301 }
302 if (!super.equals(obj)) {
303 return false;
304 }
305 if (!(obj instanceof ARP)) {
306 return false;
307 }
308 final ARP other = (ARP) obj;
309 if (this.hardwareAddressLength != other.hardwareAddressLength) {
310 return false;
311 }
312 if (this.hardwareType != other.hardwareType) {
313 return false;
314 }
315 if (this.opCode != other.opCode) {
316 return false;
317 }
318 if (this.protocolAddressLength != other.protocolAddressLength) {
319 return false;
320 }
321 if (this.protocolType != other.protocolType) {
322 return false;
323 }
324 if (!Arrays.equals(this.senderHardwareAddress,
325 other.senderHardwareAddress)) {
326 return false;
327 }
328 if (!Arrays.equals(this.senderProtocolAddress,
329 other.senderProtocolAddress)) {
330 return false;
331 }
332 if (!Arrays.equals(this.targetHardwareAddress,
333 other.targetHardwareAddress)) {
334 return false;
335 }
336 if (!Arrays.equals(this.targetProtocolAddress,
337 other.targetProtocolAddress)) {
338 return false;
339 }
340 return true;
341 }
342
Pingping Linc9e16bf2015-04-10 14:42:41 -0700343 /**
344 * Builds an ARP reply based on a request.
345 *
346 * @param srcIp the IP address to use as the reply source
347 * @param srcMac the MAC address to use as the reply source
348 * @param request the ARP request we got
349 * @return an Ethernet frame containing the ARP reply
350 */
351 public static Ethernet buildArpReply(Ip4Address srcIp, MacAddress srcMac,
352 Ethernet request) {
353
354 Ethernet eth = new Ethernet();
355 eth.setDestinationMACAddress(request.getSourceMAC());
356 eth.setSourceMACAddress(srcMac);
357 eth.setEtherType(Ethernet.TYPE_ARP);
358 eth.setVlanID(request.getVlanID());
359
360 ARP arp = new ARP();
361 arp.setOpCode(ARP.OP_REPLY);
362 arp.setProtocolType(ARP.PROTO_TYPE_IP);
363 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
364
365 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
366 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
367 arp.setSenderHardwareAddress(srcMac.toBytes());
368 arp.setTargetHardwareAddress(request.getSourceMACAddress());
369
370 arp.setTargetProtocolAddress(((ARP) request.getPayload())
Jonathan Hart2a655752015-04-07 16:46:33 -0700371 .getSenderProtocolAddress());
Pingping Linc9e16bf2015-04-10 14:42:41 -0700372 arp.setSenderProtocolAddress(srcIp.toInt());
373
374 eth.setPayload(arp);
375 return eth;
376 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700377
378 /**
379 * Deserializer function for ARP packets.
380 *
381 * @return deserializer function
382 */
383 public static Deserializer<ARP> deserializer() {
384 return (data, offset, length) -> {
385 checkInput(data, offset, length, INITIAL_HEADER_LENGTH);
386
387 ARP arp = new ARP();
388 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
389 arp.setHardwareType(bb.getShort());
390 arp.setProtocolType(bb.getShort());
391
392 byte hwAddressLength = bb.get();
393 arp.setHardwareAddressLength(hwAddressLength);
394
395 byte protocolAddressLength = bb.get();
396 arp.setProtocolAddressLength(protocolAddressLength);
397 arp.setOpCode(bb.getShort());
398
399 // Check we have enough space for the addresses
400 checkHeaderLength(length, INITIAL_HEADER_LENGTH +
401 2 * hwAddressLength +
402 2 * protocolAddressLength);
403
404 arp.senderHardwareAddress = new byte[0xff & hwAddressLength];
405 bb.get(arp.senderHardwareAddress, 0, arp.senderHardwareAddress.length);
406 arp.senderProtocolAddress = new byte[0xff & protocolAddressLength];
407 bb.get(arp.senderProtocolAddress, 0, arp.senderProtocolAddress.length);
408 arp.targetHardwareAddress = new byte[0xff & hwAddressLength];
409 bb.get(arp.targetHardwareAddress, 0, arp.targetHardwareAddress.length);
410 arp.targetProtocolAddress = new byte[0xff & protocolAddressLength];
411 bb.get(arp.targetProtocolAddress, 0, arp.targetProtocolAddress.length);
412
413 return arp;
414 };
415 }
416
Jian Li5fc14292015-12-04 11:30:46 -0800417 @Override
418 public String toString() {
419 return toStringHelper(getClass())
420 .add("hardwareType", Short.toString(hardwareType))
421 .add("protocolType", Short.toString(protocolType))
422 .add("hardwareAddressLength", Byte.toString(hardwareAddressLength))
423 .add("protocolAddressLength", Byte.toString(protocolAddressLength))
424 .add("opCode", Short.toString(opCode))
Charles Chand2edd472016-10-17 18:03:37 -0700425 .add("senderHardwareAddress", MacAddress.valueOf(senderHardwareAddress))
426 .add("senderProtocolAddress", Ip4Address.valueOf(senderProtocolAddress))
427 .add("targetHardwareAddress", MacAddress.valueOf(targetHardwareAddress))
428 .add("targetProtocolAddress", Ip4Address.valueOf(targetProtocolAddress))
Jian Li5fc14292015-12-04 11:30:46 -0800429 .toString();
430 }
alshabibc4901cd2014-09-05 16:50:40 -0700431}