blob: 56ade0e20cd1d5cf2e09f191141f22808e231e01 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
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 /**
Pier Ventre78e73f62016-12-02 19:59:28 -0800344 * Builds an ARP request using the supplied parameters.
345 *
346 * @param senderMacAddress the mac address of the sender
347 * @param senderIpAddress the ip address of the sender
348 * @param targetAddress the address to resolve
349 * @param vlanId the vlan id
350 * @return the Ethernet frame containing the ARP request
351 */
352 public static Ethernet buildArpRequest(byte[] senderMacAddress,
353 byte[] senderIpAddress,
354 byte[] targetAddress,
355 short vlanId) {
356
357 if (senderMacAddress.length != MacAddress.MAC_ADDRESS_LENGTH ||
358 senderIpAddress.length != Ip4Address.BYTE_LENGTH ||
359 targetAddress.length != Ip4Address.BYTE_LENGTH) {
360 return null;
361 }
362
363 ARP arpRequest = new ARP();
364 arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
365 .setProtocolType(ARP.PROTO_TYPE_IP)
366 .setHardwareAddressLength(
367 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
368 .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
369 .setOpCode(ARP.OP_REQUEST)
370 .setSenderHardwareAddress(senderMacAddress)
371 .setTargetHardwareAddress(MacAddress.ZERO.toBytes())
372 .setSenderProtocolAddress(senderIpAddress)
373 .setTargetProtocolAddress(targetAddress);
374
375 Ethernet eth = new Ethernet();
376 eth.setDestinationMACAddress(MacAddress.BROADCAST.toBytes())
377 .setSourceMACAddress(senderMacAddress)
378 .setEtherType(Ethernet.TYPE_ARP)
379 .setVlanID(vlanId)
380 .setPayload(arpRequest);
381 return eth;
382 }
383
384 /**
Pingping Linc9e16bf2015-04-10 14:42:41 -0700385 * Builds an ARP reply based on a request.
386 *
387 * @param srcIp the IP address to use as the reply source
388 * @param srcMac the MAC address to use as the reply source
389 * @param request the ARP request we got
390 * @return an Ethernet frame containing the ARP reply
391 */
392 public static Ethernet buildArpReply(Ip4Address srcIp, MacAddress srcMac,
393 Ethernet request) {
394
395 Ethernet eth = new Ethernet();
396 eth.setDestinationMACAddress(request.getSourceMAC());
397 eth.setSourceMACAddress(srcMac);
398 eth.setEtherType(Ethernet.TYPE_ARP);
399 eth.setVlanID(request.getVlanID());
400
401 ARP arp = new ARP();
402 arp.setOpCode(ARP.OP_REPLY);
403 arp.setProtocolType(ARP.PROTO_TYPE_IP);
404 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
405
406 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
407 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
408 arp.setSenderHardwareAddress(srcMac.toBytes());
409 arp.setTargetHardwareAddress(request.getSourceMACAddress());
410
411 arp.setTargetProtocolAddress(((ARP) request.getPayload())
Jonathan Hart2a655752015-04-07 16:46:33 -0700412 .getSenderProtocolAddress());
Pingping Linc9e16bf2015-04-10 14:42:41 -0700413 arp.setSenderProtocolAddress(srcIp.toInt());
414
415 eth.setPayload(arp);
416 return eth;
417 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700418
419 /**
420 * Deserializer function for ARP packets.
421 *
422 * @return deserializer function
423 */
424 public static Deserializer<ARP> deserializer() {
425 return (data, offset, length) -> {
426 checkInput(data, offset, length, INITIAL_HEADER_LENGTH);
427
428 ARP arp = new ARP();
429 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
430 arp.setHardwareType(bb.getShort());
431 arp.setProtocolType(bb.getShort());
432
433 byte hwAddressLength = bb.get();
434 arp.setHardwareAddressLength(hwAddressLength);
435
436 byte protocolAddressLength = bb.get();
437 arp.setProtocolAddressLength(protocolAddressLength);
438 arp.setOpCode(bb.getShort());
439
440 // Check we have enough space for the addresses
441 checkHeaderLength(length, INITIAL_HEADER_LENGTH +
442 2 * hwAddressLength +
443 2 * protocolAddressLength);
444
445 arp.senderHardwareAddress = new byte[0xff & hwAddressLength];
446 bb.get(arp.senderHardwareAddress, 0, arp.senderHardwareAddress.length);
447 arp.senderProtocolAddress = new byte[0xff & protocolAddressLength];
448 bb.get(arp.senderProtocolAddress, 0, arp.senderProtocolAddress.length);
449 arp.targetHardwareAddress = new byte[0xff & hwAddressLength];
450 bb.get(arp.targetHardwareAddress, 0, arp.targetHardwareAddress.length);
451 arp.targetProtocolAddress = new byte[0xff & protocolAddressLength];
452 bb.get(arp.targetProtocolAddress, 0, arp.targetProtocolAddress.length);
453
454 return arp;
455 };
456 }
457
Jian Li5fc14292015-12-04 11:30:46 -0800458 @Override
459 public String toString() {
460 return toStringHelper(getClass())
461 .add("hardwareType", Short.toString(hardwareType))
462 .add("protocolType", Short.toString(protocolType))
463 .add("hardwareAddressLength", Byte.toString(hardwareAddressLength))
464 .add("protocolAddressLength", Byte.toString(protocolAddressLength))
465 .add("opCode", Short.toString(opCode))
Charles Chand2edd472016-10-17 18:03:37 -0700466 .add("senderHardwareAddress", MacAddress.valueOf(senderHardwareAddress))
467 .add("senderProtocolAddress", Ip4Address.valueOf(senderProtocolAddress))
468 .add("targetHardwareAddress", MacAddress.valueOf(targetHardwareAddress))
469 .add("targetProtocolAddress", Ip4Address.valueOf(targetProtocolAddress))
Jian Li5fc14292015-12-04 11:30:46 -0800470 .toString();
471 }
alshabibc4901cd2014-09-05 16:50:40 -0700472}