blob: 5ea0cadd348c6eca50acafee934bc23521817b93 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 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))
425 .add("senderHardwareAddress", Arrays.toString(senderHardwareAddress))
426 .add("senderProtocolAddress", Arrays.toString(senderProtocolAddress))
427 .add("targetHardwareAddress", Arrays.toString(targetHardwareAddress))
428 .add("targetProtocolAddress", Arrays.toString(targetProtocolAddress))
429 .toString();
430 }
alshabibc4901cd2014-09-05 16:50:40 -0700431}