blob: dc3c07f159e240192b32c16dde0455383e16a316 [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
17
alshabibc4901cd2014-09-05 16:50:40 -070018
19package org.onlab.packet;
20
21import java.nio.ByteBuffer;
22import java.util.Arrays;
23
Jonathan Hart2a655752015-04-07 16:46:33 -070024import static org.onlab.packet.PacketUtils.*;
25
alshabibc4901cd2014-09-05 16:50:40 -070026/**
27 *
alshabib638dc712014-09-05 18:03:45 -070028 *
alshabibc4901cd2014-09-05 16:50:40 -070029 */
30public class ARP extends BasePacket {
31 public static final short HW_TYPE_ETHERNET = 0x1;
32
33 public static final short PROTO_TYPE_IP = 0x800;
34
35 public static final short OP_REQUEST = 0x1;
36 public static final short OP_REPLY = 0x2;
37 public static final short OP_RARP_REQUEST = 0x3;
38 public static final short OP_RARP_REPLY = 0x4;
39
Jonathan Hart2a655752015-04-07 16:46:33 -070040 public static final short INITIAL_HEADER_LENGTH = 8;
41
alshabibc4901cd2014-09-05 16:50:40 -070042 protected short hardwareType;
43 protected short protocolType;
44 protected byte hardwareAddressLength;
45 protected byte protocolAddressLength;
46 protected short opCode;
47 protected byte[] senderHardwareAddress;
48 protected byte[] senderProtocolAddress;
49 protected byte[] targetHardwareAddress;
50 protected byte[] targetProtocolAddress;
51
52 /**
53 * @return the hardwareType
54 */
55 public short getHardwareType() {
56 return this.hardwareType;
57 }
58
59 /**
tom5f18cf32014-09-13 14:10:57 -070060 * @param hwType
alshabibc4901cd2014-09-05 16:50:40 -070061 * the hardwareType to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -080062 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070063 */
64 public ARP setHardwareType(final short hwType) {
65 this.hardwareType = hwType;
66 return this;
67 }
68
69 /**
70 * @return the protocolType
71 */
72 public short getProtocolType() {
73 return this.protocolType;
74 }
75
76 /**
tom5f18cf32014-09-13 14:10:57 -070077 * @param protoType
alshabibc4901cd2014-09-05 16:50:40 -070078 * the protocolType to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -080079 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070080 */
81 public ARP setProtocolType(final short protoType) {
82 this.protocolType = protoType;
83 return this;
84 }
85
86 /**
87 * @return the hardwareAddressLength
88 */
89 public byte getHardwareAddressLength() {
90 return this.hardwareAddressLength;
91 }
92
93 /**
94 * @param hwAddressLength
95 * the hardwareAddressLength to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -080096 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070097 */
98 public ARP setHardwareAddressLength(final byte hwAddressLength) {
99 this.hardwareAddressLength = hwAddressLength;
100 return this;
101 }
102
103 /**
104 * @return the protocolAddressLength
105 */
106 public byte getProtocolAddressLength() {
107 return this.protocolAddressLength;
108 }
109
110 /**
tom5f18cf32014-09-13 14:10:57 -0700111 * @param protoAddressLength
alshabibc4901cd2014-09-05 16:50:40 -0700112 * the protocolAddressLength to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800113 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700114 */
115 public ARP setProtocolAddressLength(final byte protoAddressLength) {
116 this.protocolAddressLength = protoAddressLength;
117 return this;
118 }
119
120 /**
121 * @return the opCode
122 */
123 public short getOpCode() {
124 return this.opCode;
125 }
126
127 /**
tom5f18cf32014-09-13 14:10:57 -0700128 * @param op
alshabibc4901cd2014-09-05 16:50:40 -0700129 * the opCode to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800130 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700131 */
132 public ARP setOpCode(final short op) {
133 this.opCode = op;
134 return this;
135 }
136
137 /**
138 * @return the senderHardwareAddress
139 */
140 public byte[] getSenderHardwareAddress() {
141 return this.senderHardwareAddress;
142 }
143
144 /**
tom5f18cf32014-09-13 14:10:57 -0700145 * @param senderHWAddress
alshabibc4901cd2014-09-05 16:50:40 -0700146 * the senderHardwareAddress to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800147 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700148 */
149 public ARP setSenderHardwareAddress(final byte[] senderHWAddress) {
150 this.senderHardwareAddress = senderHWAddress;
151 return this;
152 }
153
154 /**
155 * @return the senderProtocolAddress
156 */
157 public byte[] getSenderProtocolAddress() {
158 return this.senderProtocolAddress;
159 }
160
161 /**
tom5f18cf32014-09-13 14:10:57 -0700162 * @param senderProtoAddress
alshabibc4901cd2014-09-05 16:50:40 -0700163 * the senderProtocolAddress to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800164 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700165 */
166 public ARP setSenderProtocolAddress(final byte[] senderProtoAddress) {
167 this.senderProtocolAddress = senderProtoAddress;
168 return this;
169 }
170
171 public ARP setSenderProtocolAddress(final int address) {
172 this.senderProtocolAddress = ByteBuffer.allocate(4).putInt(address)
173 .array();
174 return this;
175 }
176
177 /**
178 * @return the targetHardwareAddress
179 */
180 public byte[] getTargetHardwareAddress() {
181 return this.targetHardwareAddress;
182 }
183
184 /**
tom5f18cf32014-09-13 14:10:57 -0700185 * @param targetHWAddress
alshabibc4901cd2014-09-05 16:50:40 -0700186 * the targetHardwareAddress to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800187 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700188 */
189 public ARP setTargetHardwareAddress(final byte[] targetHWAddress) {
190 this.targetHardwareAddress = targetHWAddress;
191 return this;
192 }
193
194 /**
195 * @return the targetProtocolAddress
196 */
197 public byte[] getTargetProtocolAddress() {
198 return this.targetProtocolAddress;
199 }
200
201 /**
202 * @return True if gratuitous ARP (SPA = TPA), false otherwise
203 */
204 public boolean isGratuitous() {
205 assert this.senderProtocolAddress.length == this.targetProtocolAddress.length;
206
207 int indx = 0;
208 while (indx < this.senderProtocolAddress.length) {
209 if (this.senderProtocolAddress[indx] != this.targetProtocolAddress[indx]) {
210 return false;
211 }
212 indx++;
213 }
214
215 return true;
216 }
217
218 /**
tom5f18cf32014-09-13 14:10:57 -0700219 * @param targetProtoAddress
alshabibc4901cd2014-09-05 16:50:40 -0700220 * the targetProtocolAddress to set
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800221 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700222 */
223 public ARP setTargetProtocolAddress(final byte[] targetProtoAddress) {
224 this.targetProtocolAddress = targetProtoAddress;
225 return this;
226 }
227
228 public ARP setTargetProtocolAddress(final int address) {
229 this.targetProtocolAddress = ByteBuffer.allocate(4).putInt(address)
230 .array();
231 return this;
232 }
233
234 @Override
235 public byte[] serialize() {
236 final int length = 8 + 2 * (0xff & this.hardwareAddressLength) + 2
237 * (0xff & this.protocolAddressLength);
238 final byte[] data = new byte[length];
239 final ByteBuffer bb = ByteBuffer.wrap(data);
240 bb.putShort(this.hardwareType);
241 bb.putShort(this.protocolType);
242 bb.put(this.hardwareAddressLength);
243 bb.put(this.protocolAddressLength);
244 bb.putShort(this.opCode);
245 bb.put(this.senderHardwareAddress, 0, 0xff & this.hardwareAddressLength);
246 bb.put(this.senderProtocolAddress, 0, 0xff & this.protocolAddressLength);
247 bb.put(this.targetHardwareAddress, 0, 0xff & this.hardwareAddressLength);
248 bb.put(this.targetProtocolAddress, 0, 0xff & this.protocolAddressLength);
249 return data;
250 }
251
252 @Override
253 public IPacket deserialize(final byte[] data, final int offset,
Jonathan Hart2a655752015-04-07 16:46:33 -0700254 final int length) {
alshabibc4901cd2014-09-05 16:50:40 -0700255 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
256 this.hardwareType = bb.getShort();
257 this.protocolType = bb.getShort();
258 this.hardwareAddressLength = bb.get();
259 this.protocolAddressLength = bb.get();
260 this.opCode = bb.getShort();
261 this.senderHardwareAddress = new byte[0xff & this.hardwareAddressLength];
262 bb.get(this.senderHardwareAddress, 0, this.senderHardwareAddress.length);
263 this.senderProtocolAddress = new byte[0xff & this.protocolAddressLength];
264 bb.get(this.senderProtocolAddress, 0, this.senderProtocolAddress.length);
265 this.targetHardwareAddress = new byte[0xff & this.hardwareAddressLength];
266 bb.get(this.targetHardwareAddress, 0, this.targetHardwareAddress.length);
267 this.targetProtocolAddress = new byte[0xff & this.protocolAddressLength];
268 bb.get(this.targetProtocolAddress, 0, this.targetProtocolAddress.length);
269 return this;
270 }
271
272 /*
273 * (non-Javadoc)
274 *
275 * @see java.lang.Object#hashCode()
276 */
277 @Override
278 public int hashCode() {
279 final int prime = 13121;
280 int result = super.hashCode();
281 result = prime * result + this.hardwareAddressLength;
282 result = prime * result + this.hardwareType;
283 result = prime * result + this.opCode;
284 result = prime * result + this.protocolAddressLength;
285 result = prime * result + this.protocolType;
286 result = prime * result + Arrays.hashCode(this.senderHardwareAddress);
287 result = prime * result + Arrays.hashCode(this.senderProtocolAddress);
288 result = prime * result + Arrays.hashCode(this.targetHardwareAddress);
289 result = prime * result + Arrays.hashCode(this.targetProtocolAddress);
290 return result;
291 }
292
293 /*
294 * (non-Javadoc)
295 *
296 * @see java.lang.Object#equals(java.lang.Object)
297 */
298 @Override
299 public boolean equals(final Object obj) {
300 if (this == obj) {
301 return true;
302 }
303 if (!super.equals(obj)) {
304 return false;
305 }
306 if (!(obj instanceof ARP)) {
307 return false;
308 }
309 final ARP other = (ARP) obj;
310 if (this.hardwareAddressLength != other.hardwareAddressLength) {
311 return false;
312 }
313 if (this.hardwareType != other.hardwareType) {
314 return false;
315 }
316 if (this.opCode != other.opCode) {
317 return false;
318 }
319 if (this.protocolAddressLength != other.protocolAddressLength) {
320 return false;
321 }
322 if (this.protocolType != other.protocolType) {
323 return false;
324 }
325 if (!Arrays.equals(this.senderHardwareAddress,
326 other.senderHardwareAddress)) {
327 return false;
328 }
329 if (!Arrays.equals(this.senderProtocolAddress,
330 other.senderProtocolAddress)) {
331 return false;
332 }
333 if (!Arrays.equals(this.targetHardwareAddress,
334 other.targetHardwareAddress)) {
335 return false;
336 }
337 if (!Arrays.equals(this.targetProtocolAddress,
338 other.targetProtocolAddress)) {
339 return false;
340 }
341 return true;
342 }
343
344 /*
345 * (non-Javadoc)
346 *
347 * @see java.lang.Object#toString()
348 */
349 @Override
350 public String toString() {
351 return "ARP [hardwareType=" + this.hardwareType + ", protocolType="
352 + this.protocolType + ", hardwareAddressLength="
353 + this.hardwareAddressLength + ", protocolAddressLength="
354 + this.protocolAddressLength + ", opCode=" + this.opCode
355 + ", senderHardwareAddress="
356 + Arrays.toString(this.senderHardwareAddress)
357 + ", senderProtocolAddress="
358 + Arrays.toString(this.senderProtocolAddress)
359 + ", targetHardwareAddress="
360 + Arrays.toString(this.targetHardwareAddress)
361 + ", targetProtocolAddress="
362 + Arrays.toString(this.targetProtocolAddress) + "]";
363 }
Pingping Linc9e16bf2015-04-10 14:42:41 -0700364
365 /**
366 * Builds an ARP reply based on a request.
367 *
368 * @param srcIp the IP address to use as the reply source
369 * @param srcMac the MAC address to use as the reply source
370 * @param request the ARP request we got
371 * @return an Ethernet frame containing the ARP reply
372 */
373 public static Ethernet buildArpReply(Ip4Address srcIp, MacAddress srcMac,
374 Ethernet request) {
375
376 Ethernet eth = new Ethernet();
377 eth.setDestinationMACAddress(request.getSourceMAC());
378 eth.setSourceMACAddress(srcMac);
379 eth.setEtherType(Ethernet.TYPE_ARP);
380 eth.setVlanID(request.getVlanID());
381
382 ARP arp = new ARP();
383 arp.setOpCode(ARP.OP_REPLY);
384 arp.setProtocolType(ARP.PROTO_TYPE_IP);
385 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
386
387 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
388 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
389 arp.setSenderHardwareAddress(srcMac.toBytes());
390 arp.setTargetHardwareAddress(request.getSourceMACAddress());
391
392 arp.setTargetProtocolAddress(((ARP) request.getPayload())
Jonathan Hart2a655752015-04-07 16:46:33 -0700393 .getSenderProtocolAddress());
Pingping Linc9e16bf2015-04-10 14:42:41 -0700394 arp.setSenderProtocolAddress(srcIp.toInt());
395
396 eth.setPayload(arp);
397 return eth;
398 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700399
400 /**
401 * Deserializer function for ARP packets.
402 *
403 * @return deserializer function
404 */
405 public static Deserializer<ARP> deserializer() {
406 return (data, offset, length) -> {
407 checkInput(data, offset, length, INITIAL_HEADER_LENGTH);
408
409 ARP arp = new ARP();
410 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
411 arp.setHardwareType(bb.getShort());
412 arp.setProtocolType(bb.getShort());
413
414 byte hwAddressLength = bb.get();
415 arp.setHardwareAddressLength(hwAddressLength);
416
417 byte protocolAddressLength = bb.get();
418 arp.setProtocolAddressLength(protocolAddressLength);
419 arp.setOpCode(bb.getShort());
420
421 // Check we have enough space for the addresses
422 checkHeaderLength(length, INITIAL_HEADER_LENGTH +
423 2 * hwAddressLength +
424 2 * protocolAddressLength);
425
426 arp.senderHardwareAddress = new byte[0xff & hwAddressLength];
427 bb.get(arp.senderHardwareAddress, 0, arp.senderHardwareAddress.length);
428 arp.senderProtocolAddress = new byte[0xff & protocolAddressLength];
429 bb.get(arp.senderProtocolAddress, 0, arp.senderProtocolAddress.length);
430 arp.targetHardwareAddress = new byte[0xff & hwAddressLength];
431 bb.get(arp.targetHardwareAddress, 0, arp.targetHardwareAddress.length);
432 arp.targetProtocolAddress = new byte[0xff & protocolAddressLength];
433 bb.get(arp.targetProtocolAddress, 0, arp.targetProtocolAddress.length);
434
435 return arp;
436 };
437 }
438
alshabibc4901cd2014-09-05 16:50:40 -0700439}