blob: 773169b92bfa50fa5d27d8caf62989dd6a5ee3bb [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
Charles Chan35a32322017-08-14 11:42:11 -0700348 * @param targetMacAddress the mac address of the target
349 * @param targetIpAddress the ip address to resolve
350 * @param destinationMacAddress the mac address put in Ethernet header
Pier Ventre78e73f62016-12-02 19:59:28 -0800351 * @param vlanId the vlan id
352 * @return the Ethernet frame containing the ARP request
353 */
354 public static Ethernet buildArpRequest(byte[] senderMacAddress,
355 byte[] senderIpAddress,
Charles Chan35a32322017-08-14 11:42:11 -0700356 byte[] targetMacAddress,
357 byte[] targetIpAddress,
358 byte[] destinationMacAddress,
Pier Ventre78e73f62016-12-02 19:59:28 -0800359 short vlanId) {
360
361 if (senderMacAddress.length != MacAddress.MAC_ADDRESS_LENGTH ||
362 senderIpAddress.length != Ip4Address.BYTE_LENGTH ||
Charles Chan35a32322017-08-14 11:42:11 -0700363 targetIpAddress.length != Ip4Address.BYTE_LENGTH) {
Pier Ventre78e73f62016-12-02 19:59:28 -0800364 return null;
365 }
366
367 ARP arpRequest = new ARP();
368 arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
369 .setProtocolType(ARP.PROTO_TYPE_IP)
Charles Chan35a32322017-08-14 11:42:11 -0700370 .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
Pier Ventre78e73f62016-12-02 19:59:28 -0800371 .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
372 .setOpCode(ARP.OP_REQUEST)
373 .setSenderHardwareAddress(senderMacAddress)
Charles Chan35a32322017-08-14 11:42:11 -0700374 .setTargetHardwareAddress(targetMacAddress)
Pier Ventre78e73f62016-12-02 19:59:28 -0800375 .setSenderProtocolAddress(senderIpAddress)
Charles Chan35a32322017-08-14 11:42:11 -0700376 .setTargetProtocolAddress(targetIpAddress);
Pier Ventre78e73f62016-12-02 19:59:28 -0800377
378 Ethernet eth = new Ethernet();
Charles Chan35a32322017-08-14 11:42:11 -0700379 eth.setDestinationMACAddress(destinationMacAddress)
Pier Ventre78e73f62016-12-02 19:59:28 -0800380 .setSourceMACAddress(senderMacAddress)
381 .setEtherType(Ethernet.TYPE_ARP)
382 .setVlanID(vlanId)
Charles Chan35a32322017-08-14 11:42:11 -0700383 .setPad(true)
Pier Ventre78e73f62016-12-02 19:59:28 -0800384 .setPayload(arpRequest);
385 return eth;
386 }
387
388 /**
Charles Chan35a32322017-08-14 11:42:11 -0700389 * Builds an ARP request using the supplied parameters.
390 *
391 * @param senderMacAddress the mac address of the sender
392 * @param senderIpAddress the ip address of the sender
393 * @param targetIpAddress the ip address to resolve
394 * @param vlanId the vlan id
395 * @return the Ethernet frame containing the ARP request
396 */
397 public static Ethernet buildArpRequest(byte[] senderMacAddress,
398 byte[] senderIpAddress,
399 byte[] targetIpAddress,
400 short vlanId) {
401 return buildArpRequest(senderMacAddress, senderIpAddress,
402 MacAddress.ZERO.toBytes(), targetIpAddress,
403 MacAddress.BROADCAST.toBytes(), vlanId);
404 }
405
406 /**
Pingping Linc9e16bf2015-04-10 14:42:41 -0700407 * Builds an ARP reply based on a request.
408 *
409 * @param srcIp the IP address to use as the reply source
410 * @param srcMac the MAC address to use as the reply source
411 * @param request the ARP request we got
412 * @return an Ethernet frame containing the ARP reply
413 */
414 public static Ethernet buildArpReply(Ip4Address srcIp, MacAddress srcMac,
415 Ethernet request) {
416
417 Ethernet eth = new Ethernet();
418 eth.setDestinationMACAddress(request.getSourceMAC());
419 eth.setSourceMACAddress(srcMac);
420 eth.setEtherType(Ethernet.TYPE_ARP);
421 eth.setVlanID(request.getVlanID());
422
423 ARP arp = new ARP();
424 arp.setOpCode(ARP.OP_REPLY);
425 arp.setProtocolType(ARP.PROTO_TYPE_IP);
426 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
427
428 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
429 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
430 arp.setSenderHardwareAddress(srcMac.toBytes());
431 arp.setTargetHardwareAddress(request.getSourceMACAddress());
432
433 arp.setTargetProtocolAddress(((ARP) request.getPayload())
Jonathan Hart2a655752015-04-07 16:46:33 -0700434 .getSenderProtocolAddress());
Pingping Linc9e16bf2015-04-10 14:42:41 -0700435 arp.setSenderProtocolAddress(srcIp.toInt());
436
437 eth.setPayload(arp);
438 return eth;
439 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700440
441 /**
442 * Deserializer function for ARP packets.
443 *
444 * @return deserializer function
445 */
446 public static Deserializer<ARP> deserializer() {
447 return (data, offset, length) -> {
448 checkInput(data, offset, length, INITIAL_HEADER_LENGTH);
449
450 ARP arp = new ARP();
451 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
452 arp.setHardwareType(bb.getShort());
453 arp.setProtocolType(bb.getShort());
454
455 byte hwAddressLength = bb.get();
456 arp.setHardwareAddressLength(hwAddressLength);
457
458 byte protocolAddressLength = bb.get();
459 arp.setProtocolAddressLength(protocolAddressLength);
460 arp.setOpCode(bb.getShort());
461
462 // Check we have enough space for the addresses
463 checkHeaderLength(length, INITIAL_HEADER_LENGTH +
464 2 * hwAddressLength +
465 2 * protocolAddressLength);
466
467 arp.senderHardwareAddress = new byte[0xff & hwAddressLength];
468 bb.get(arp.senderHardwareAddress, 0, arp.senderHardwareAddress.length);
469 arp.senderProtocolAddress = new byte[0xff & protocolAddressLength];
470 bb.get(arp.senderProtocolAddress, 0, arp.senderProtocolAddress.length);
471 arp.targetHardwareAddress = new byte[0xff & hwAddressLength];
472 bb.get(arp.targetHardwareAddress, 0, arp.targetHardwareAddress.length);
473 arp.targetProtocolAddress = new byte[0xff & protocolAddressLength];
474 bb.get(arp.targetProtocolAddress, 0, arp.targetProtocolAddress.length);
475
476 return arp;
477 };
478 }
479
Jian Li5fc14292015-12-04 11:30:46 -0800480 @Override
481 public String toString() {
482 return toStringHelper(getClass())
483 .add("hardwareType", Short.toString(hardwareType))
484 .add("protocolType", Short.toString(protocolType))
485 .add("hardwareAddressLength", Byte.toString(hardwareAddressLength))
486 .add("protocolAddressLength", Byte.toString(protocolAddressLength))
487 .add("opCode", Short.toString(opCode))
Charles Chand2edd472016-10-17 18:03:37 -0700488 .add("senderHardwareAddress", MacAddress.valueOf(senderHardwareAddress))
489 .add("senderProtocolAddress", Ip4Address.valueOf(senderProtocolAddress))
490 .add("targetHardwareAddress", MacAddress.valueOf(targetHardwareAddress))
491 .add("targetProtocolAddress", Ip4Address.valueOf(targetProtocolAddress))
Jian Li5fc14292015-12-04 11:30:46 -0800492 .toString();
493 }
alshabibc4901cd2014-09-05 16:50:40 -0700494}