blob: ab33e80f355d21856173feec637fb6448d88c779 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 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
Charles Chan119eeb52015-10-27 12:40:25 -070021import org.onlab.packet.ndp.NeighborAdvertisement;
22import org.onlab.packet.ndp.NeighborSolicitation;
23import org.onlab.packet.ndp.Redirect;
24import org.onlab.packet.ndp.RouterAdvertisement;
25import org.onlab.packet.ndp.RouterSolicitation;
26
alshabibc4901cd2014-09-05 16:50:40 -070027import java.nio.ByteBuffer;
28import java.util.Arrays;
29import java.util.HashMap;
30import java.util.Map;
31
Jonathan Hart2a655752015-04-07 16:46:33 -070032import static com.google.common.base.Preconditions.checkNotNull;
33import static org.onlab.packet.PacketUtils.checkHeaderLength;
34import static org.onlab.packet.PacketUtils.checkInput;
alshabibc4901cd2014-09-05 16:50:40 -070035
36/**
Jian Li5fc14292015-12-04 11:30:46 -080037 * Ethernet Packet.
alshabibc4901cd2014-09-05 16:50:40 -070038 */
39public class Ethernet extends BasePacket {
40 private static final String HEXES = "0123456789ABCDEF";
Thomas Vachuska5dd52f72014-11-28 19:27:45 -080041
alshabib7b808c52015-06-26 14:22:24 -070042 public static final short TYPE_ARP = EthType.EtherType.ARP.ethType().toShort();
43 public static final short TYPE_RARP = EthType.EtherType.RARP.ethType().toShort();
44 public static final short TYPE_IPV4 = EthType.EtherType.IPV4.ethType().toShort();
45 public static final short TYPE_IPV6 = EthType.EtherType.IPV6.ethType().toShort();
46 public static final short TYPE_LLDP = EthType.EtherType.LLDP.ethType().toShort();
47 public static final short TYPE_VLAN = EthType.EtherType.VLAN.ethType().toShort();
48 public static final short TYPE_BSN = EthType.EtherType.BDDP.ethType().toShort();
49
50 public static final short MPLS_UNICAST = EthType.EtherType.MPLS_UNICAST.ethType().toShort();;
51 public static final short MPLS_MULTICAST = EthType.EtherType.MPLS_MULTICAST.ethType().toShort();
alshabibcaf1ca22015-06-25 15:18:16 -070052
Jonathan Hart2a655752015-04-07 16:46:33 -070053
alshabibcaf1ca22015-06-25 15:18:16 -070054 public static final short VLAN_UNTAGGED = (short) 0xffff;
Jonathan Hart2a655752015-04-07 16:46:33 -070055
56 public static final short ETHERNET_HEADER_LENGTH = 14; // bytes
57 public static final short VLAN_HEADER_LENGTH = 4; // bytes
58
alshabibc4901cd2014-09-05 16:50:40 -070059 public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
Jonathan Hart2a655752015-04-07 16:46:33 -070060
61 private static final Map<Short, Deserializer<? extends IPacket>> ETHERTYPE_DESERIALIZER_MAP =
62 new HashMap<>();
alshabibc4901cd2014-09-05 16:50:40 -070063
64 static {
alshabibcaf1ca22015-06-25 15:18:16 -070065 for (EthType.EtherType ethType : EthType.EtherType.values()) {
alshabib7b808c52015-06-26 14:22:24 -070066 if (ethType.deserializer() != null) {
Jonathan Hart2a655752015-04-07 16:46:33 -070067 ETHERTYPE_DESERIALIZER_MAP.put(ethType.ethType().toShort(), ethType.deserializer());
alshabibcaf1ca22015-06-25 15:18:16 -070068 }
69 }
alshabibc4901cd2014-09-05 16:50:40 -070070 }
71
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070072 protected MacAddress destinationMACAddress;
73 protected MacAddress sourceMACAddress;
alshabibc4901cd2014-09-05 16:50:40 -070074 protected byte priorityCode;
75 protected short vlanID;
76 protected short etherType;
77 protected boolean pad = false;
78
79 /**
80 * By default, set Ethernet to untagged.
81 */
82 public Ethernet() {
83 super();
84 this.vlanID = Ethernet.VLAN_UNTAGGED;
85 }
86
87 /**
88 * Gets the destination MAC address.
89 *
90 * @return the destination MAC as a byte array
91 */
92 public byte[] getDestinationMACAddress() {
93 return this.destinationMACAddress.toBytes();
94 }
95
96 /**
97 * Gets the destination MAC address.
98 *
99 * @return the destination MAC
100 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700101 public MacAddress getDestinationMAC() {
alshabibc4901cd2014-09-05 16:50:40 -0700102 return this.destinationMACAddress;
103 }
104
105 /**
106 * Sets the destination MAC address.
107 *
tom5f18cf32014-09-13 14:10:57 -0700108 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700109 * @return the Ethernet frame
110 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800111 public Ethernet setDestinationMACAddress(final MacAddress destMac) {
112 this.destinationMACAddress = checkNotNull(destMac);
113 return this;
114 }
115
116 /**
117 * Sets the destination MAC address.
118 *
119 * @param destMac the destination MAC to set
120 * @return the Ethernet frame
121 */
alshabibc4901cd2014-09-05 16:50:40 -0700122 public Ethernet setDestinationMACAddress(final byte[] destMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700123 this.destinationMACAddress = MacAddress.valueOf(destMac);
alshabibc4901cd2014-09-05 16:50:40 -0700124 return this;
125 }
126
127 /**
128 * Sets the destination MAC address.
129 *
tom5f18cf32014-09-13 14:10:57 -0700130 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700131 * @return the Ethernet frame
132 */
133 public Ethernet setDestinationMACAddress(final String destMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700134 this.destinationMACAddress = MacAddress.valueOf(destMac);
alshabibc4901cd2014-09-05 16:50:40 -0700135 return this;
136 }
137
138 /**
139 * Gets the source MAC address.
140 *
141 * @return the source MACAddress as a byte array
142 */
143 public byte[] getSourceMACAddress() {
144 return this.sourceMACAddress.toBytes();
145 }
146
147 /**
148 * Gets the source MAC address.
149 *
150 * @return the source MACAddress
151 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700152 public MacAddress getSourceMAC() {
alshabibc4901cd2014-09-05 16:50:40 -0700153 return this.sourceMACAddress;
154 }
155
156 /**
157 * Sets the source MAC address.
158 *
tom5f18cf32014-09-13 14:10:57 -0700159 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700160 * @return the Ethernet frame
161 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800162 public Ethernet setSourceMACAddress(final MacAddress sourceMac) {
163 this.sourceMACAddress = checkNotNull(sourceMac);
164 return this;
165 }
166
167 /**
168 * Sets the source MAC address.
169 *
170 * @param sourceMac the source MAC to set
171 * @return the Ethernet frame
172 */
alshabibc4901cd2014-09-05 16:50:40 -0700173 public Ethernet setSourceMACAddress(final byte[] sourceMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700174 this.sourceMACAddress = MacAddress.valueOf(sourceMac);
alshabibc4901cd2014-09-05 16:50:40 -0700175 return this;
176 }
177
178 /**
179 * Sets the source MAC address.
180 *
tom5f18cf32014-09-13 14:10:57 -0700181 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700182 * @return the Ethernet frame
183 */
184 public Ethernet setSourceMACAddress(final String sourceMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700185 this.sourceMACAddress = MacAddress.valueOf(sourceMac);
alshabibc4901cd2014-09-05 16:50:40 -0700186 return this;
187 }
188
189 /**
190 * Gets the priority code.
191 *
192 * @return the priorityCode
193 */
194 public byte getPriorityCode() {
195 return this.priorityCode;
196 }
197
198 /**
199 * Sets the priority code.
200 *
tom5f18cf32014-09-13 14:10:57 -0700201 * @param priority the priorityCode to set
alshabibc4901cd2014-09-05 16:50:40 -0700202 * @return the Ethernet frame
203 */
204 public Ethernet setPriorityCode(final byte priority) {
205 this.priorityCode = priority;
206 return this;
207 }
208
209 /**
210 * Gets the VLAN ID.
211 *
212 * @return the vlanID
213 */
214 public short getVlanID() {
215 return this.vlanID;
216 }
217
218 /**
219 * Sets the VLAN ID.
220 *
tom5f18cf32014-09-13 14:10:57 -0700221 * @param vlan the vlanID to set
alshabibc4901cd2014-09-05 16:50:40 -0700222 * @return the Ethernet frame
223 */
224 public Ethernet setVlanID(final short vlan) {
225 this.vlanID = vlan;
226 return this;
227 }
228
229 /**
230 * Gets the Ethernet type.
231 *
232 * @return the etherType
233 */
234 public short getEtherType() {
235 return this.etherType;
236 }
237
238 /**
239 * Sets the Ethernet type.
240 *
tom5f18cf32014-09-13 14:10:57 -0700241 * @param ethType the etherType to set
alshabibc4901cd2014-09-05 16:50:40 -0700242 * @return the Ethernet frame
243 */
244 public Ethernet setEtherType(final short ethType) {
245 this.etherType = ethType;
246 return this;
247 }
248
249 /**
250 * @return True if the Ethernet frame is broadcast, false otherwise
251 */
252 public boolean isBroadcast() {
253 assert this.destinationMACAddress.length() == 6;
254 return this.destinationMACAddress.isBroadcast();
255 }
256
257 /**
258 * @return True is the Ethernet frame is multicast, False otherwise
259 */
260 public boolean isMulticast() {
261 return this.destinationMACAddress.isMulticast();
262 }
263
264 /**
265 * Pad this packet to 60 bytes minimum, filling with zeros?
266 *
267 * @return the pad
268 */
269 public boolean isPad() {
270 return this.pad;
271 }
272
273 /**
274 * Pad this packet to 60 bytes minimum, filling with zeros?
275 *
tom5f18cf32014-09-13 14:10:57 -0700276 * @param pd
alshabibc4901cd2014-09-05 16:50:40 -0700277 * the pad to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800278 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700279 */
280 public Ethernet setPad(final boolean pd) {
281 this.pad = pd;
282 return this;
283 }
284
285 @Override
286 public byte[] serialize() {
287 byte[] payloadData = null;
288 if (this.payload != null) {
289 this.payload.setParent(this);
290 payloadData = this.payload.serialize();
291 }
292 int length = 14 + (this.vlanID == Ethernet.VLAN_UNTAGGED ? 0 : 4)
293 + (payloadData == null ? 0 : payloadData.length);
294 if (this.pad && length < 60) {
295 length = 60;
296 }
297 final byte[] data = new byte[length];
298 final ByteBuffer bb = ByteBuffer.wrap(data);
299 bb.put(this.destinationMACAddress.toBytes());
300 bb.put(this.sourceMACAddress.toBytes());
301 if (this.vlanID != Ethernet.VLAN_UNTAGGED) {
alshabib10580802015-02-18 18:30:33 -0800302 bb.putShort(TYPE_VLAN);
alshabibc4901cd2014-09-05 16:50:40 -0700303 bb.putShort((short) (this.priorityCode << 13 | this.vlanID & 0x0fff));
304 }
305 bb.putShort(this.etherType);
306 if (payloadData != null) {
307 bb.put(payloadData);
308 }
309 if (this.pad) {
310 Arrays.fill(data, bb.position(), data.length, (byte) 0x0);
311 }
312 return data;
313 }
314
315 @Override
316 public IPacket deserialize(final byte[] data, final int offset,
Jonathan Hart2a655752015-04-07 16:46:33 -0700317 final int length) {
alshabibc4901cd2014-09-05 16:50:40 -0700318 if (length <= 0) {
319 return null;
320 }
321 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
322 if (this.destinationMACAddress == null) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700323 this.destinationMACAddress = MacAddress.valueOf(new byte[6]);
alshabibc4901cd2014-09-05 16:50:40 -0700324 }
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700325 final byte[] dstAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
alshabibc4901cd2014-09-05 16:50:40 -0700326 bb.get(dstAddr);
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700327 this.destinationMACAddress = MacAddress.valueOf(dstAddr);
alshabibc4901cd2014-09-05 16:50:40 -0700328
329 if (this.sourceMACAddress == null) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700330 this.sourceMACAddress = MacAddress.valueOf(new byte[6]);
alshabibc4901cd2014-09-05 16:50:40 -0700331 }
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700332 final byte[] srcAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
alshabibc4901cd2014-09-05 16:50:40 -0700333 bb.get(srcAddr);
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700334 this.sourceMACAddress = MacAddress.valueOf(srcAddr);
alshabibc4901cd2014-09-05 16:50:40 -0700335
336 short ethType = bb.getShort();
alshabib10580802015-02-18 18:30:33 -0800337 if (ethType == TYPE_VLAN) {
alshabibc4901cd2014-09-05 16:50:40 -0700338 final short tci = bb.getShort();
339 this.priorityCode = (byte) (tci >> 13 & 0x07);
340 this.vlanID = (short) (tci & 0x0fff);
341 ethType = bb.getShort();
342 } else {
343 this.vlanID = Ethernet.VLAN_UNTAGGED;
344 }
345 this.etherType = ethType;
346
347 IPacket payload;
Jonathan Hart2a655752015-04-07 16:46:33 -0700348 Deserializer<? extends IPacket> deserializer;
349 if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
350 deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
alshabibc4901cd2014-09-05 16:50:40 -0700351 } else {
Jonathan Hart2a655752015-04-07 16:46:33 -0700352 deserializer = Data.deserializer();
alshabibc4901cd2014-09-05 16:50:40 -0700353 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700354 try {
355 this.payload = deserializer.deserialize(data, bb.position(),
356 bb.limit() - bb.position());
357 this.payload.setParent(this);
358 } catch (DeserializationException e) {
359 return this;
360 }
alshabibc4901cd2014-09-05 16:50:40 -0700361 return this;
362 }
363
364 /**
365 * Checks to see if a string is a valid MAC address.
366 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800367 * @param macAddress string to test if it is a valid MAC
alshabibc4901cd2014-09-05 16:50:40 -0700368 * @return True if macAddress is a valid MAC, False otherwise
369 */
370 public static boolean isMACAddress(final String macAddress) {
371 final String[] macBytes = macAddress.split(":");
372 if (macBytes.length != 6) {
373 return false;
374 }
375 for (int i = 0; i < 6; ++i) {
376 if (Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1
377 || Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(
378 1)) == -1) {
379 return false;
380 }
381 }
382 return true;
383 }
384
385 /**
386 * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
387 * matter, and returns a corresponding byte[].
388 *
389 * @param macAddress
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800390 * The MAC address to convert into a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700391 * @return The macAddress as a byte array
392 */
393 public static byte[] toMACAddress(final String macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700394 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700395 }
396
397 /**
398 * Accepts a MAC address and returns the corresponding long, where the MAC
399 * bytes are set on the lower order bytes of the long.
400 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800401 * @param macAddress MAC address as a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700402 * @return a long containing the mac address bytes
403 */
404 public static long toLong(final byte[] macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700405 return MacAddress.valueOf(macAddress).toLong();
alshabibc4901cd2014-09-05 16:50:40 -0700406 }
407
408 /**
409 * Converts a long MAC address to a byte array.
410 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800411 * @param macAddress MAC address set on the lower order bytes of the long
alshabibc4901cd2014-09-05 16:50:40 -0700412 * @return the bytes of the mac address
413 */
414 public static byte[] toByteArray(final long macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700415 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700416 }
417
418 /*
419 * (non-Javadoc)
420 *
421 * @see java.lang.Object#hashCode()
422 */
423 @Override
424 public int hashCode() {
425 final int prime = 7867;
426 int result = super.hashCode();
427 result = prime * result + this.destinationMACAddress.hashCode();
428 result = prime * result + this.etherType;
429 result = prime * result + this.vlanID;
430 result = prime * result + this.priorityCode;
431 result = prime * result + (this.pad ? 1231 : 1237);
432 result = prime * result + this.sourceMACAddress.hashCode();
433 return result;
434 }
435
436 /*
437 * (non-Javadoc)
438 *
439 * @see java.lang.Object#equals(java.lang.Object)
440 */
441 @Override
442 public boolean equals(final Object obj) {
443 if (this == obj) {
444 return true;
445 }
446 if (!super.equals(obj)) {
447 return false;
448 }
449 if (!(obj instanceof Ethernet)) {
450 return false;
451 }
452 final Ethernet other = (Ethernet) obj;
453 if (!this.destinationMACAddress.equals(other.destinationMACAddress)) {
454 return false;
455 }
456 if (this.priorityCode != other.priorityCode) {
457 return false;
458 }
459 if (this.vlanID != other.vlanID) {
460 return false;
461 }
462 if (this.etherType != other.etherType) {
463 return false;
464 }
465 if (this.pad != other.pad) {
466 return false;
467 }
468 if (!this.sourceMACAddress.equals(other.sourceMACAddress)) {
469 return false;
470 }
471 return true;
472 }
473
474 /*
475 * (non-Javadoc)
476 *
477 * @see java.lang.Object#toString(java.lang.Object)
478 */
479 @Override
480 public String toString() {
481
482 final StringBuffer sb = new StringBuffer("\n");
483
484 final IPacket pkt = this.getPayload();
485
486 if (pkt instanceof ARP) {
487 sb.append("arp");
488 } else if (pkt instanceof LLDP) {
489 sb.append("lldp");
490 } else if (pkt instanceof ICMP) {
491 sb.append("icmp");
492 } else if (pkt instanceof IPv4) {
493 sb.append("ip");
494 } else if (pkt instanceof DHCP) {
495 sb.append("dhcp");
496 } else {
497 sb.append(this.getEtherType());
498 }
499
500 sb.append("\ndl_vlan: ");
501 if (this.getVlanID() == Ethernet.VLAN_UNTAGGED) {
502 sb.append("untagged");
503 } else {
504 sb.append(this.getVlanID());
505 }
506 sb.append("\ndl_vlan_pcp: ");
507 sb.append(this.getPriorityCode());
508 sb.append("\ndl_src: ");
509 sb.append(bytesToHex(this.getSourceMACAddress()));
510 sb.append("\ndl_dst: ");
511 sb.append(bytesToHex(this.getDestinationMACAddress()));
512
513 if (pkt instanceof ARP) {
514 final ARP p = (ARP) pkt;
515 sb.append("\nnw_src: ");
516 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
517 .getSenderProtocolAddress())));
518 sb.append("\nnw_dst: ");
519 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
520 .getTargetProtocolAddress())));
521 } else if (pkt instanceof LLDP) {
522 sb.append("lldp packet");
523 } else if (pkt instanceof ICMP) {
524 final ICMP icmp = (ICMP) pkt;
525 sb.append("\nicmp_type: ");
526 sb.append(icmp.getIcmpType());
527 sb.append("\nicmp_code: ");
528 sb.append(icmp.getIcmpCode());
529 } else if (pkt instanceof IPv4) {
530 final IPv4 p = (IPv4) pkt;
531 sb.append("\nnw_src: ");
532 sb.append(IPv4.fromIPv4Address(p.getSourceAddress()));
533 sb.append("\nnw_dst: ");
534 sb.append(IPv4.fromIPv4Address(p.getDestinationAddress()));
535 sb.append("\nnw_tos: ");
536 sb.append(p.getDiffServ());
537 sb.append("\nnw_proto: ");
538 sb.append(p.getProtocol());
539
Charles Chan119eeb52015-10-27 12:40:25 -0700540 IPacket payload = pkt.getPayload();
541 if (payload != null) {
542 if (payload instanceof TCP) {
543 sb.append("\ntp_src: ");
544 sb.append(((TCP) payload).getSourcePort());
545 sb.append("\ntp_dst: ");
546 sb.append(((TCP) payload).getDestinationPort());
alshabibc4901cd2014-09-05 16:50:40 -0700547
Charles Chan119eeb52015-10-27 12:40:25 -0700548 } else if (payload instanceof UDP) {
549 sb.append("\ntp_src: ");
550 sb.append(((UDP) payload).getSourcePort());
551 sb.append("\ntp_dst: ");
552 sb.append(((UDP) payload).getDestinationPort());
553 } else if (payload instanceof ICMP) {
554 final ICMP icmp = (ICMP) payload;
555 sb.append("\nicmp_type: ");
556 sb.append(icmp.getIcmpType());
557 sb.append("\nicmp_code: ");
558 sb.append(icmp.getIcmpCode());
559 }
alshabibc4901cd2014-09-05 16:50:40 -0700560 }
Charles Chan119eeb52015-10-27 12:40:25 -0700561 } else if (pkt instanceof IPv6) {
562 final IPv6 ipv6 = (IPv6) pkt;
563 sb.append("\nipv6_src: ");
564 sb.append(Ip6Address.valueOf(ipv6.getSourceAddress()).toString());
565 sb.append("\nipv6_dst: ");
566 sb.append(Ip6Address.valueOf(ipv6.getDestinationAddress()).toString());
567 sb.append("\nipv6_proto: ");
568 sb.append(ipv6.getNextHeader());
alshabibc4901cd2014-09-05 16:50:40 -0700569
Charles Chan119eeb52015-10-27 12:40:25 -0700570 IPacket payload = pkt.getPayload();
571 if (payload != null && payload instanceof ICMP6) {
572 final ICMP6 icmp6 = (ICMP6) payload;
573 sb.append("\nicmp6_type: ");
574 sb.append(icmp6.getIcmpType());
575 sb.append("\nicmp6_code: ");
576 sb.append(icmp6.getIcmpCode());
577
578 payload = payload.getPayload();
579 if (payload != null) {
580 if (payload instanceof NeighborSolicitation) {
581 final NeighborSolicitation ns = (NeighborSolicitation) payload;
582 sb.append("\nns_target_addr: ");
583 sb.append(Ip6Address.valueOf(ns.getTargetAddress()).toString());
584 ns.getOptions().forEach(option -> {
585 sb.append("\noption_type: ");
586 sb.append(option.type());
587 sb.append("\noption_data: ");
588 sb.append(bytesToHex(option.data()));
589 });
590 } else if (payload instanceof NeighborAdvertisement) {
591 final NeighborAdvertisement na = (NeighborAdvertisement) payload;
592 sb.append("\nna_target_addr: ");
593 sb.append(Ip6Address.valueOf(na.getTargetAddress()).toString());
594 sb.append("\nna_solicited_flag: ");
595 sb.append(na.getSolicitedFlag());
596 sb.append("\nna_router_flag: ");
597 sb.append(na.getRouterFlag());
598 sb.append("\nna_override_flag: ");
599 sb.append(na.getOverrideFlag());
600 na.getOptions().forEach(option -> {
601 sb.append("\noption_type: ");
602 sb.append(option.type());
603 sb.append("\noption_data: ");
604 sb.append(bytesToHex(option.data()));
605 });
606 } else if (payload instanceof RouterSolicitation) {
607 final RouterSolicitation rs = (RouterSolicitation) payload;
608 sb.append("\nrs");
609 rs.getOptions().forEach(option -> {
610 sb.append("\noption_type: ");
611 sb.append(option.type());
612 sb.append("\noption_data: ");
613 sb.append(bytesToHex(option.data()));
614 });
615 } else if (payload instanceof RouterAdvertisement) {
616 final RouterAdvertisement ra = (RouterAdvertisement) payload;
617 sb.append("\nra_hop_limit: ");
618 sb.append(ra.getCurrentHopLimit());
619 sb.append("\nra_mflag: ");
620 sb.append(ra.getMFlag());
621 sb.append("\nra_oflag: ");
622 sb.append(ra.getOFlag());
623 sb.append("\nra_reachable_time: ");
624 sb.append(ra.getReachableTime());
625 sb.append("\nra_retransmit_time: ");
626 sb.append(ra.getRetransmitTimer());
627 sb.append("\nra_router_lifetime: ");
628 sb.append(ra.getRouterLifetime());
629 ra.getOptions().forEach(option -> {
630 sb.append("\noption_type: ");
631 sb.append(option.type());
632 sb.append("\noption_data: ");
633 sb.append(bytesToHex(option.data()));
634 });
635 } else if (payload instanceof Redirect) {
636 final Redirect rd = (Redirect) payload;
637 sb.append("\nrd_target_addr: ");
638 sb.append(Ip6Address.valueOf(rd.getTargetAddress()).toString());
639 rd.getOptions().forEach(option -> {
640 sb.append("\noption_type: ");
641 sb.append(option.type());
642 sb.append("\noption_data: ");
643 sb.append(bytesToHex(option.data()));
644 });
645 }
646 }
alshabibc4901cd2014-09-05 16:50:40 -0700647 }
alshabibc4901cd2014-09-05 16:50:40 -0700648 } else if (pkt instanceof DHCP) {
649 sb.append("\ndhcp packet");
650 } else if (pkt instanceof Data) {
651 sb.append("\ndata packet");
652 } else if (pkt instanceof LLC) {
653 sb.append("\nllc packet");
654 } else {
tom5f18cf32014-09-13 14:10:57 -0700655 sb.append("\nunknown packet");
alshabibc4901cd2014-09-05 16:50:40 -0700656 }
657
658 return sb.toString();
659 }
660
661 public static String bytesToHex(byte[] in) {
662 final StringBuilder builder = new StringBuilder();
663 for (byte b : in) {
664 builder.append(String.format("%02x", b));
665 }
666 return builder.toString();
667 }
668
Jonathan Hart2a655752015-04-07 16:46:33 -0700669 /**
670 * Deserializer function for Ethernet packets.
671 *
672 * @return deserializer function
673 */
674 public static Deserializer<Ethernet> deserializer() {
675 return (data, offset, length) -> {
676 checkInput(data, offset, length, ETHERNET_HEADER_LENGTH);
677
678 byte[] addressBuffer = new byte[DATALAYER_ADDRESS_LENGTH];
679
680 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
681 Ethernet eth = new Ethernet();
682 // Read destination MAC address into buffer
683 bb.get(addressBuffer);
684 eth.setDestinationMACAddress(addressBuffer);
685
686 // Read source MAC address into buffer
687 bb.get(addressBuffer);
688 eth.setSourceMACAddress(addressBuffer);
689
690 short ethType = bb.getShort();
691 if (ethType == TYPE_VLAN) {
692 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
693 final short tci = bb.getShort();
694 eth.setPriorityCode((byte) (tci >> 13 & 0x07));
695 eth.setVlanID((short) (tci & 0x0fff));
696 ethType = bb.getShort();
697 } else {
698 eth.setVlanID(Ethernet.VLAN_UNTAGGED);
699 }
700 eth.setEtherType(ethType);
701
702 IPacket payload;
703 Deserializer<? extends IPacket> deserializer;
704 if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
705 deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
706 } else {
707 deserializer = Data.deserializer();
708 }
709 payload = deserializer.deserialize(data, bb.position(),
710 bb.limit() - bb.position());
711 payload.setParent(eth);
712 eth.setPayload(payload);
713
714 return eth;
715 };
716 }
alshabibc4901cd2014-09-05 16:50:40 -0700717}