blob: 998062c26ba9d9c80f0a3e6df647d0de8ea958c4 [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
alshabibc4901cd2014-09-05 16:50:40 -0700251
252 /*
253 * (non-Javadoc)
254 *
255 * @see java.lang.Object#hashCode()
256 */
257 @Override
258 public int hashCode() {
259 final int prime = 13121;
260 int result = super.hashCode();
261 result = prime * result + this.hardwareAddressLength;
262 result = prime * result + this.hardwareType;
263 result = prime * result + this.opCode;
264 result = prime * result + this.protocolAddressLength;
265 result = prime * result + this.protocolType;
266 result = prime * result + Arrays.hashCode(this.senderHardwareAddress);
267 result = prime * result + Arrays.hashCode(this.senderProtocolAddress);
268 result = prime * result + Arrays.hashCode(this.targetHardwareAddress);
269 result = prime * result + Arrays.hashCode(this.targetProtocolAddress);
270 return result;
271 }
272
273 /*
274 * (non-Javadoc)
275 *
276 * @see java.lang.Object#equals(java.lang.Object)
277 */
278 @Override
279 public boolean equals(final Object obj) {
280 if (this == obj) {
281 return true;
282 }
283 if (!super.equals(obj)) {
284 return false;
285 }
286 if (!(obj instanceof ARP)) {
287 return false;
288 }
289 final ARP other = (ARP) obj;
290 if (this.hardwareAddressLength != other.hardwareAddressLength) {
291 return false;
292 }
293 if (this.hardwareType != other.hardwareType) {
294 return false;
295 }
296 if (this.opCode != other.opCode) {
297 return false;
298 }
299 if (this.protocolAddressLength != other.protocolAddressLength) {
300 return false;
301 }
302 if (this.protocolType != other.protocolType) {
303 return false;
304 }
305 if (!Arrays.equals(this.senderHardwareAddress,
306 other.senderHardwareAddress)) {
307 return false;
308 }
309 if (!Arrays.equals(this.senderProtocolAddress,
310 other.senderProtocolAddress)) {
311 return false;
312 }
313 if (!Arrays.equals(this.targetHardwareAddress,
314 other.targetHardwareAddress)) {
315 return false;
316 }
317 if (!Arrays.equals(this.targetProtocolAddress,
318 other.targetProtocolAddress)) {
319 return false;
320 }
321 return true;
322 }
323
Pingping Linc9e16bf2015-04-10 14:42:41 -0700324 /**
Pier Ventre78e73f62016-12-02 19:59:28 -0800325 * Builds an ARP request using the supplied parameters.
326 *
327 * @param senderMacAddress the mac address of the sender
328 * @param senderIpAddress the ip address of the sender
Charles Chan35a32322017-08-14 11:42:11 -0700329 * @param targetMacAddress the mac address of the target
330 * @param targetIpAddress the ip address to resolve
331 * @param destinationMacAddress the mac address put in Ethernet header
Pier Ventre78e73f62016-12-02 19:59:28 -0800332 * @param vlanId the vlan id
333 * @return the Ethernet frame containing the ARP request
334 */
335 public static Ethernet buildArpRequest(byte[] senderMacAddress,
336 byte[] senderIpAddress,
Charles Chan35a32322017-08-14 11:42:11 -0700337 byte[] targetMacAddress,
338 byte[] targetIpAddress,
339 byte[] destinationMacAddress,
Pier Ventre78e73f62016-12-02 19:59:28 -0800340 short vlanId) {
341
342 if (senderMacAddress.length != MacAddress.MAC_ADDRESS_LENGTH ||
343 senderIpAddress.length != Ip4Address.BYTE_LENGTH ||
Charles Chan35a32322017-08-14 11:42:11 -0700344 targetIpAddress.length != Ip4Address.BYTE_LENGTH) {
Pier Ventre78e73f62016-12-02 19:59:28 -0800345 return null;
346 }
347
348 ARP arpRequest = new ARP();
349 arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
350 .setProtocolType(ARP.PROTO_TYPE_IP)
Charles Chan35a32322017-08-14 11:42:11 -0700351 .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
Pier Ventre78e73f62016-12-02 19:59:28 -0800352 .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
353 .setOpCode(ARP.OP_REQUEST)
354 .setSenderHardwareAddress(senderMacAddress)
Charles Chan35a32322017-08-14 11:42:11 -0700355 .setTargetHardwareAddress(targetMacAddress)
Pier Ventre78e73f62016-12-02 19:59:28 -0800356 .setSenderProtocolAddress(senderIpAddress)
Charles Chan35a32322017-08-14 11:42:11 -0700357 .setTargetProtocolAddress(targetIpAddress);
Pier Ventre78e73f62016-12-02 19:59:28 -0800358
359 Ethernet eth = new Ethernet();
Charles Chan35a32322017-08-14 11:42:11 -0700360 eth.setDestinationMACAddress(destinationMacAddress)
Pier Ventre78e73f62016-12-02 19:59:28 -0800361 .setSourceMACAddress(senderMacAddress)
362 .setEtherType(Ethernet.TYPE_ARP)
363 .setVlanID(vlanId)
Charles Chan35a32322017-08-14 11:42:11 -0700364 .setPad(true)
Pier Ventre78e73f62016-12-02 19:59:28 -0800365 .setPayload(arpRequest);
366 return eth;
367 }
368
369 /**
Charles Chan35a32322017-08-14 11:42:11 -0700370 * Builds an ARP request using the supplied parameters.
371 *
372 * @param senderMacAddress the mac address of the sender
373 * @param senderIpAddress the ip address of the sender
374 * @param targetIpAddress the ip address to resolve
375 * @param vlanId the vlan id
376 * @return the Ethernet frame containing the ARP request
377 */
378 public static Ethernet buildArpRequest(byte[] senderMacAddress,
379 byte[] senderIpAddress,
380 byte[] targetIpAddress,
381 short vlanId) {
382 return buildArpRequest(senderMacAddress, senderIpAddress,
383 MacAddress.ZERO.toBytes(), targetIpAddress,
384 MacAddress.BROADCAST.toBytes(), vlanId);
385 }
386
387 /**
Pingping Linc9e16bf2015-04-10 14:42:41 -0700388 * Builds an ARP reply based on a request.
389 *
390 * @param srcIp the IP address to use as the reply source
391 * @param srcMac the MAC address to use as the reply source
392 * @param request the ARP request we got
393 * @return an Ethernet frame containing the ARP reply
394 */
395 public static Ethernet buildArpReply(Ip4Address srcIp, MacAddress srcMac,
396 Ethernet request) {
397
398 Ethernet eth = new Ethernet();
399 eth.setDestinationMACAddress(request.getSourceMAC());
400 eth.setSourceMACAddress(srcMac);
401 eth.setEtherType(Ethernet.TYPE_ARP);
Jonghwan Hyun800d9d02018-04-09 09:40:50 -0700402 eth.setQinQVID(request.getQinQVID());
403 eth.setQinQTPID(request.getQinQTPID());
Pingping Linc9e16bf2015-04-10 14:42:41 -0700404 eth.setVlanID(request.getVlanID());
405
406 ARP arp = new ARP();
407 arp.setOpCode(ARP.OP_REPLY);
408 arp.setProtocolType(ARP.PROTO_TYPE_IP);
409 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
410
411 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
412 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
413 arp.setSenderHardwareAddress(srcMac.toBytes());
414 arp.setTargetHardwareAddress(request.getSourceMACAddress());
415
416 arp.setTargetProtocolAddress(((ARP) request.getPayload())
Jonathan Hart2a655752015-04-07 16:46:33 -0700417 .getSenderProtocolAddress());
Pingping Linc9e16bf2015-04-10 14:42:41 -0700418 arp.setSenderProtocolAddress(srcIp.toInt());
419
420 eth.setPayload(arp);
421 return eth;
422 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700423
424 /**
425 * Deserializer function for ARP packets.
426 *
427 * @return deserializer function
428 */
429 public static Deserializer<ARP> deserializer() {
430 return (data, offset, length) -> {
431 checkInput(data, offset, length, INITIAL_HEADER_LENGTH);
432
433 ARP arp = new ARP();
434 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
435 arp.setHardwareType(bb.getShort());
436 arp.setProtocolType(bb.getShort());
437
438 byte hwAddressLength = bb.get();
439 arp.setHardwareAddressLength(hwAddressLength);
440
441 byte protocolAddressLength = bb.get();
442 arp.setProtocolAddressLength(protocolAddressLength);
443 arp.setOpCode(bb.getShort());
444
445 // Check we have enough space for the addresses
446 checkHeaderLength(length, INITIAL_HEADER_LENGTH +
447 2 * hwAddressLength +
448 2 * protocolAddressLength);
449
450 arp.senderHardwareAddress = new byte[0xff & hwAddressLength];
451 bb.get(arp.senderHardwareAddress, 0, arp.senderHardwareAddress.length);
452 arp.senderProtocolAddress = new byte[0xff & protocolAddressLength];
453 bb.get(arp.senderProtocolAddress, 0, arp.senderProtocolAddress.length);
454 arp.targetHardwareAddress = new byte[0xff & hwAddressLength];
455 bb.get(arp.targetHardwareAddress, 0, arp.targetHardwareAddress.length);
456 arp.targetProtocolAddress = new byte[0xff & protocolAddressLength];
457 bb.get(arp.targetProtocolAddress, 0, arp.targetProtocolAddress.length);
458
459 return arp;
460 };
461 }
462
Ray Milkeyf0c47612017-09-28 11:29:38 -0700463 /**
464 * Make an exact copy of the ARP packet.
465 *
466 * @return copy of the packet
467 */
468 public ARP duplicate() {
469 try {
470 byte[] data = serialize();
471 return deserializer().deserialize(data, 0, data.length);
472 } catch (DeserializationException dex) {
473 // If we can't make an object out of the serialized data, its a defect
474 throw new IllegalStateException(dex);
475 }
476 }
477
Jian Li5fc14292015-12-04 11:30:46 -0800478 @Override
479 public String toString() {
480 return toStringHelper(getClass())
481 .add("hardwareType", Short.toString(hardwareType))
482 .add("protocolType", Short.toString(protocolType))
483 .add("hardwareAddressLength", Byte.toString(hardwareAddressLength))
484 .add("protocolAddressLength", Byte.toString(protocolAddressLength))
485 .add("opCode", Short.toString(opCode))
Charles Chand2edd472016-10-17 18:03:37 -0700486 .add("senderHardwareAddress", MacAddress.valueOf(senderHardwareAddress))
487 .add("senderProtocolAddress", Ip4Address.valueOf(senderProtocolAddress))
488 .add("targetHardwareAddress", MacAddress.valueOf(targetHardwareAddress))
489 .add("targetProtocolAddress", Ip4Address.valueOf(targetProtocolAddress))
Jian Li5fc14292015-12-04 11:30:46 -0800490 .toString();
491 }
alshabibc4901cd2014-09-05 16:50:40 -0700492}