blob: 003c17727718b58bdea12e6cce331706afbe60cf [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
21import java.nio.ByteBuffer;
22import java.util.Arrays;
23import java.util.HashMap;
24import java.util.Map;
25
Jonathan Hart2a655752015-04-07 16:46:33 -070026import static com.google.common.base.Preconditions.checkNotNull;
27import static org.onlab.packet.PacketUtils.checkHeaderLength;
28import static org.onlab.packet.PacketUtils.checkInput;
alshabibc4901cd2014-09-05 16:50:40 -070029
30/**
31 *
alshabibc4901cd2014-09-05 16:50:40 -070032 */
33public class Ethernet extends BasePacket {
34 private static final String HEXES = "0123456789ABCDEF";
Thomas Vachuska5dd52f72014-11-28 19:27:45 -080035
alshabib7b808c52015-06-26 14:22:24 -070036 public static final short TYPE_ARP = EthType.EtherType.ARP.ethType().toShort();
37 public static final short TYPE_RARP = EthType.EtherType.RARP.ethType().toShort();
38 public static final short TYPE_IPV4 = EthType.EtherType.IPV4.ethType().toShort();
39 public static final short TYPE_IPV6 = EthType.EtherType.IPV6.ethType().toShort();
40 public static final short TYPE_LLDP = EthType.EtherType.LLDP.ethType().toShort();
41 public static final short TYPE_VLAN = EthType.EtherType.VLAN.ethType().toShort();
42 public static final short TYPE_BSN = EthType.EtherType.BDDP.ethType().toShort();
43
44 public static final short MPLS_UNICAST = EthType.EtherType.MPLS_UNICAST.ethType().toShort();;
45 public static final short MPLS_MULTICAST = EthType.EtherType.MPLS_MULTICAST.ethType().toShort();
alshabibcaf1ca22015-06-25 15:18:16 -070046
Jonathan Hart2a655752015-04-07 16:46:33 -070047
alshabibcaf1ca22015-06-25 15:18:16 -070048 public static final short VLAN_UNTAGGED = (short) 0xffff;
Jonathan Hart2a655752015-04-07 16:46:33 -070049
50 public static final short ETHERNET_HEADER_LENGTH = 14; // bytes
51 public static final short VLAN_HEADER_LENGTH = 4; // bytes
52
alshabibc4901cd2014-09-05 16:50:40 -070053 public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
Jonathan Hart2a655752015-04-07 16:46:33 -070054
55 private static final Map<Short, Deserializer<? extends IPacket>> ETHERTYPE_DESERIALIZER_MAP =
56 new HashMap<>();
alshabibc4901cd2014-09-05 16:50:40 -070057
58 static {
alshabibcaf1ca22015-06-25 15:18:16 -070059 for (EthType.EtherType ethType : EthType.EtherType.values()) {
alshabib7b808c52015-06-26 14:22:24 -070060 if (ethType.deserializer() != null) {
Jonathan Hart2a655752015-04-07 16:46:33 -070061 ETHERTYPE_DESERIALIZER_MAP.put(ethType.ethType().toShort(), ethType.deserializer());
alshabibcaf1ca22015-06-25 15:18:16 -070062 }
63 }
alshabibc4901cd2014-09-05 16:50:40 -070064 }
65
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070066 protected MacAddress destinationMACAddress;
67 protected MacAddress sourceMACAddress;
alshabibc4901cd2014-09-05 16:50:40 -070068 protected byte priorityCode;
69 protected short vlanID;
70 protected short etherType;
71 protected boolean pad = false;
72
73 /**
74 * By default, set Ethernet to untagged.
75 */
76 public Ethernet() {
77 super();
78 this.vlanID = Ethernet.VLAN_UNTAGGED;
79 }
80
81 /**
82 * Gets the destination MAC address.
83 *
84 * @return the destination MAC as a byte array
85 */
86 public byte[] getDestinationMACAddress() {
87 return this.destinationMACAddress.toBytes();
88 }
89
90 /**
91 * Gets the destination MAC address.
92 *
93 * @return the destination MAC
94 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070095 public MacAddress getDestinationMAC() {
alshabibc4901cd2014-09-05 16:50:40 -070096 return this.destinationMACAddress;
97 }
98
99 /**
100 * Sets the destination MAC address.
101 *
tom5f18cf32014-09-13 14:10:57 -0700102 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700103 * @return the Ethernet frame
104 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800105 public Ethernet setDestinationMACAddress(final MacAddress destMac) {
106 this.destinationMACAddress = checkNotNull(destMac);
107 return this;
108 }
109
110 /**
111 * Sets the destination MAC address.
112 *
113 * @param destMac the destination MAC to set
114 * @return the Ethernet frame
115 */
alshabibc4901cd2014-09-05 16:50:40 -0700116 public Ethernet setDestinationMACAddress(final byte[] destMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700117 this.destinationMACAddress = MacAddress.valueOf(destMac);
alshabibc4901cd2014-09-05 16:50:40 -0700118 return this;
119 }
120
121 /**
122 * Sets the destination MAC address.
123 *
tom5f18cf32014-09-13 14:10:57 -0700124 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700125 * @return the Ethernet frame
126 */
127 public Ethernet setDestinationMACAddress(final String destMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700128 this.destinationMACAddress = MacAddress.valueOf(destMac);
alshabibc4901cd2014-09-05 16:50:40 -0700129 return this;
130 }
131
132 /**
133 * Gets the source MAC address.
134 *
135 * @return the source MACAddress as a byte array
136 */
137 public byte[] getSourceMACAddress() {
138 return this.sourceMACAddress.toBytes();
139 }
140
141 /**
142 * Gets the source MAC address.
143 *
144 * @return the source MACAddress
145 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700146 public MacAddress getSourceMAC() {
alshabibc4901cd2014-09-05 16:50:40 -0700147 return this.sourceMACAddress;
148 }
149
150 /**
151 * Sets the source MAC address.
152 *
tom5f18cf32014-09-13 14:10:57 -0700153 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700154 * @return the Ethernet frame
155 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800156 public Ethernet setSourceMACAddress(final MacAddress sourceMac) {
157 this.sourceMACAddress = checkNotNull(sourceMac);
158 return this;
159 }
160
161 /**
162 * Sets the source MAC address.
163 *
164 * @param sourceMac the source MAC to set
165 * @return the Ethernet frame
166 */
alshabibc4901cd2014-09-05 16:50:40 -0700167 public Ethernet setSourceMACAddress(final byte[] sourceMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700168 this.sourceMACAddress = MacAddress.valueOf(sourceMac);
alshabibc4901cd2014-09-05 16:50:40 -0700169 return this;
170 }
171
172 /**
173 * Sets the source MAC address.
174 *
tom5f18cf32014-09-13 14:10:57 -0700175 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700176 * @return the Ethernet frame
177 */
178 public Ethernet setSourceMACAddress(final String sourceMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700179 this.sourceMACAddress = MacAddress.valueOf(sourceMac);
alshabibc4901cd2014-09-05 16:50:40 -0700180 return this;
181 }
182
183 /**
184 * Gets the priority code.
185 *
186 * @return the priorityCode
187 */
188 public byte getPriorityCode() {
189 return this.priorityCode;
190 }
191
192 /**
193 * Sets the priority code.
194 *
tom5f18cf32014-09-13 14:10:57 -0700195 * @param priority the priorityCode to set
alshabibc4901cd2014-09-05 16:50:40 -0700196 * @return the Ethernet frame
197 */
198 public Ethernet setPriorityCode(final byte priority) {
199 this.priorityCode = priority;
200 return this;
201 }
202
203 /**
204 * Gets the VLAN ID.
205 *
206 * @return the vlanID
207 */
208 public short getVlanID() {
209 return this.vlanID;
210 }
211
212 /**
213 * Sets the VLAN ID.
214 *
tom5f18cf32014-09-13 14:10:57 -0700215 * @param vlan the vlanID to set
alshabibc4901cd2014-09-05 16:50:40 -0700216 * @return the Ethernet frame
217 */
218 public Ethernet setVlanID(final short vlan) {
219 this.vlanID = vlan;
220 return this;
221 }
222
223 /**
224 * Gets the Ethernet type.
225 *
226 * @return the etherType
227 */
228 public short getEtherType() {
229 return this.etherType;
230 }
231
232 /**
233 * Sets the Ethernet type.
234 *
tom5f18cf32014-09-13 14:10:57 -0700235 * @param ethType the etherType to set
alshabibc4901cd2014-09-05 16:50:40 -0700236 * @return the Ethernet frame
237 */
238 public Ethernet setEtherType(final short ethType) {
239 this.etherType = ethType;
240 return this;
241 }
242
243 /**
244 * @return True if the Ethernet frame is broadcast, false otherwise
245 */
246 public boolean isBroadcast() {
247 assert this.destinationMACAddress.length() == 6;
248 return this.destinationMACAddress.isBroadcast();
249 }
250
251 /**
252 * @return True is the Ethernet frame is multicast, False otherwise
253 */
254 public boolean isMulticast() {
255 return this.destinationMACAddress.isMulticast();
256 }
257
258 /**
259 * Pad this packet to 60 bytes minimum, filling with zeros?
260 *
261 * @return the pad
262 */
263 public boolean isPad() {
264 return this.pad;
265 }
266
267 /**
268 * Pad this packet to 60 bytes minimum, filling with zeros?
269 *
tom5f18cf32014-09-13 14:10:57 -0700270 * @param pd
alshabibc4901cd2014-09-05 16:50:40 -0700271 * the pad to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800272 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700273 */
274 public Ethernet setPad(final boolean pd) {
275 this.pad = pd;
276 return this;
277 }
278
279 @Override
280 public byte[] serialize() {
281 byte[] payloadData = null;
282 if (this.payload != null) {
283 this.payload.setParent(this);
284 payloadData = this.payload.serialize();
285 }
286 int length = 14 + (this.vlanID == Ethernet.VLAN_UNTAGGED ? 0 : 4)
287 + (payloadData == null ? 0 : payloadData.length);
288 if (this.pad && length < 60) {
289 length = 60;
290 }
291 final byte[] data = new byte[length];
292 final ByteBuffer bb = ByteBuffer.wrap(data);
293 bb.put(this.destinationMACAddress.toBytes());
294 bb.put(this.sourceMACAddress.toBytes());
295 if (this.vlanID != Ethernet.VLAN_UNTAGGED) {
alshabib10580802015-02-18 18:30:33 -0800296 bb.putShort(TYPE_VLAN);
alshabibc4901cd2014-09-05 16:50:40 -0700297 bb.putShort((short) (this.priorityCode << 13 | this.vlanID & 0x0fff));
298 }
299 bb.putShort(this.etherType);
300 if (payloadData != null) {
301 bb.put(payloadData);
302 }
303 if (this.pad) {
304 Arrays.fill(data, bb.position(), data.length, (byte) 0x0);
305 }
306 return data;
307 }
308
309 @Override
310 public IPacket deserialize(final byte[] data, final int offset,
Jonathan Hart2a655752015-04-07 16:46:33 -0700311 final int length) {
alshabibc4901cd2014-09-05 16:50:40 -0700312 if (length <= 0) {
313 return null;
314 }
315 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
316 if (this.destinationMACAddress == null) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700317 this.destinationMACAddress = MacAddress.valueOf(new byte[6]);
alshabibc4901cd2014-09-05 16:50:40 -0700318 }
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700319 final byte[] dstAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
alshabibc4901cd2014-09-05 16:50:40 -0700320 bb.get(dstAddr);
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700321 this.destinationMACAddress = MacAddress.valueOf(dstAddr);
alshabibc4901cd2014-09-05 16:50:40 -0700322
323 if (this.sourceMACAddress == null) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700324 this.sourceMACAddress = MacAddress.valueOf(new byte[6]);
alshabibc4901cd2014-09-05 16:50:40 -0700325 }
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700326 final byte[] srcAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
alshabibc4901cd2014-09-05 16:50:40 -0700327 bb.get(srcAddr);
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700328 this.sourceMACAddress = MacAddress.valueOf(srcAddr);
alshabibc4901cd2014-09-05 16:50:40 -0700329
330 short ethType = bb.getShort();
alshabib10580802015-02-18 18:30:33 -0800331 if (ethType == TYPE_VLAN) {
alshabibc4901cd2014-09-05 16:50:40 -0700332 final short tci = bb.getShort();
333 this.priorityCode = (byte) (tci >> 13 & 0x07);
334 this.vlanID = (short) (tci & 0x0fff);
335 ethType = bb.getShort();
336 } else {
337 this.vlanID = Ethernet.VLAN_UNTAGGED;
338 }
339 this.etherType = ethType;
340
341 IPacket payload;
Jonathan Hart2a655752015-04-07 16:46:33 -0700342 Deserializer<? extends IPacket> deserializer;
343 if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
344 deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
alshabibc4901cd2014-09-05 16:50:40 -0700345 } else {
Jonathan Hart2a655752015-04-07 16:46:33 -0700346 deserializer = Data.deserializer();
alshabibc4901cd2014-09-05 16:50:40 -0700347 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700348 try {
349 this.payload = deserializer.deserialize(data, bb.position(),
350 bb.limit() - bb.position());
351 this.payload.setParent(this);
352 } catch (DeserializationException e) {
353 return this;
354 }
alshabibc4901cd2014-09-05 16:50:40 -0700355 return this;
356 }
357
358 /**
359 * Checks to see if a string is a valid MAC address.
360 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800361 * @param macAddress string to test if it is a valid MAC
alshabibc4901cd2014-09-05 16:50:40 -0700362 * @return True if macAddress is a valid MAC, False otherwise
363 */
364 public static boolean isMACAddress(final String macAddress) {
365 final String[] macBytes = macAddress.split(":");
366 if (macBytes.length != 6) {
367 return false;
368 }
369 for (int i = 0; i < 6; ++i) {
370 if (Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1
371 || Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(
372 1)) == -1) {
373 return false;
374 }
375 }
376 return true;
377 }
378
379 /**
380 * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
381 * matter, and returns a corresponding byte[].
382 *
383 * @param macAddress
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800384 * The MAC address to convert into a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700385 * @return The macAddress as a byte array
386 */
387 public static byte[] toMACAddress(final String macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700388 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700389 }
390
391 /**
392 * Accepts a MAC address and returns the corresponding long, where the MAC
393 * bytes are set on the lower order bytes of the long.
394 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800395 * @param macAddress MAC address as a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700396 * @return a long containing the mac address bytes
397 */
398 public static long toLong(final byte[] macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700399 return MacAddress.valueOf(macAddress).toLong();
alshabibc4901cd2014-09-05 16:50:40 -0700400 }
401
402 /**
403 * Converts a long MAC address to a byte array.
404 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800405 * @param macAddress MAC address set on the lower order bytes of the long
alshabibc4901cd2014-09-05 16:50:40 -0700406 * @return the bytes of the mac address
407 */
408 public static byte[] toByteArray(final long macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700409 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700410 }
411
412 /*
413 * (non-Javadoc)
414 *
415 * @see java.lang.Object#hashCode()
416 */
417 @Override
418 public int hashCode() {
419 final int prime = 7867;
420 int result = super.hashCode();
421 result = prime * result + this.destinationMACAddress.hashCode();
422 result = prime * result + this.etherType;
423 result = prime * result + this.vlanID;
424 result = prime * result + this.priorityCode;
425 result = prime * result + (this.pad ? 1231 : 1237);
426 result = prime * result + this.sourceMACAddress.hashCode();
427 return result;
428 }
429
430 /*
431 * (non-Javadoc)
432 *
433 * @see java.lang.Object#equals(java.lang.Object)
434 */
435 @Override
436 public boolean equals(final Object obj) {
437 if (this == obj) {
438 return true;
439 }
440 if (!super.equals(obj)) {
441 return false;
442 }
443 if (!(obj instanceof Ethernet)) {
444 return false;
445 }
446 final Ethernet other = (Ethernet) obj;
447 if (!this.destinationMACAddress.equals(other.destinationMACAddress)) {
448 return false;
449 }
450 if (this.priorityCode != other.priorityCode) {
451 return false;
452 }
453 if (this.vlanID != other.vlanID) {
454 return false;
455 }
456 if (this.etherType != other.etherType) {
457 return false;
458 }
459 if (this.pad != other.pad) {
460 return false;
461 }
462 if (!this.sourceMACAddress.equals(other.sourceMACAddress)) {
463 return false;
464 }
465 return true;
466 }
467
468 /*
469 * (non-Javadoc)
470 *
471 * @see java.lang.Object#toString(java.lang.Object)
472 */
473 @Override
474 public String toString() {
475
476 final StringBuffer sb = new StringBuffer("\n");
477
478 final IPacket pkt = this.getPayload();
479
480 if (pkt instanceof ARP) {
481 sb.append("arp");
482 } else if (pkt instanceof LLDP) {
483 sb.append("lldp");
484 } else if (pkt instanceof ICMP) {
485 sb.append("icmp");
486 } else if (pkt instanceof IPv4) {
487 sb.append("ip");
488 } else if (pkt instanceof DHCP) {
489 sb.append("dhcp");
490 } else {
491 sb.append(this.getEtherType());
492 }
493
494 sb.append("\ndl_vlan: ");
495 if (this.getVlanID() == Ethernet.VLAN_UNTAGGED) {
496 sb.append("untagged");
497 } else {
498 sb.append(this.getVlanID());
499 }
500 sb.append("\ndl_vlan_pcp: ");
501 sb.append(this.getPriorityCode());
502 sb.append("\ndl_src: ");
503 sb.append(bytesToHex(this.getSourceMACAddress()));
504 sb.append("\ndl_dst: ");
505 sb.append(bytesToHex(this.getDestinationMACAddress()));
506
507 if (pkt instanceof ARP) {
508 final ARP p = (ARP) pkt;
509 sb.append("\nnw_src: ");
510 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
511 .getSenderProtocolAddress())));
512 sb.append("\nnw_dst: ");
513 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
514 .getTargetProtocolAddress())));
515 } else if (pkt instanceof LLDP) {
516 sb.append("lldp packet");
517 } else if (pkt instanceof ICMP) {
518 final ICMP icmp = (ICMP) pkt;
519 sb.append("\nicmp_type: ");
520 sb.append(icmp.getIcmpType());
521 sb.append("\nicmp_code: ");
522 sb.append(icmp.getIcmpCode());
523 } else if (pkt instanceof IPv4) {
524 final IPv4 p = (IPv4) pkt;
525 sb.append("\nnw_src: ");
526 sb.append(IPv4.fromIPv4Address(p.getSourceAddress()));
527 sb.append("\nnw_dst: ");
528 sb.append(IPv4.fromIPv4Address(p.getDestinationAddress()));
529 sb.append("\nnw_tos: ");
530 sb.append(p.getDiffServ());
531 sb.append("\nnw_proto: ");
532 sb.append(p.getProtocol());
533
534 if (pkt instanceof TCP) {
535 sb.append("\ntp_src: ");
536 sb.append(((TCP) pkt).getSourcePort());
537 sb.append("\ntp_dst: ");
538 sb.append(((TCP) pkt).getDestinationPort());
539
540 } else if (pkt instanceof UDP) {
541 sb.append("\ntp_src: ");
542 sb.append(((UDP) pkt).getSourcePort());
543 sb.append("\ntp_dst: ");
544 sb.append(((UDP) pkt).getDestinationPort());
545 }
546
547 if (pkt instanceof ICMP) {
548 final ICMP icmp = (ICMP) pkt;
549 sb.append("\nicmp_type: ");
550 sb.append(icmp.getIcmpType());
551 sb.append("\nicmp_code: ");
552 sb.append(icmp.getIcmpCode());
553 }
554
555 } else if (pkt instanceof DHCP) {
556 sb.append("\ndhcp packet");
557 } else if (pkt instanceof Data) {
558 sb.append("\ndata packet");
559 } else if (pkt instanceof LLC) {
560 sb.append("\nllc packet");
561 } else {
tom5f18cf32014-09-13 14:10:57 -0700562 sb.append("\nunknown packet");
alshabibc4901cd2014-09-05 16:50:40 -0700563 }
564
565 return sb.toString();
566 }
567
568 public static String bytesToHex(byte[] in) {
569 final StringBuilder builder = new StringBuilder();
570 for (byte b : in) {
571 builder.append(String.format("%02x", b));
572 }
573 return builder.toString();
574 }
575
Jonathan Hart2a655752015-04-07 16:46:33 -0700576 /**
577 * Deserializer function for Ethernet packets.
578 *
579 * @return deserializer function
580 */
581 public static Deserializer<Ethernet> deserializer() {
582 return (data, offset, length) -> {
583 checkInput(data, offset, length, ETHERNET_HEADER_LENGTH);
584
585 byte[] addressBuffer = new byte[DATALAYER_ADDRESS_LENGTH];
586
587 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
588 Ethernet eth = new Ethernet();
589 // Read destination MAC address into buffer
590 bb.get(addressBuffer);
591 eth.setDestinationMACAddress(addressBuffer);
592
593 // Read source MAC address into buffer
594 bb.get(addressBuffer);
595 eth.setSourceMACAddress(addressBuffer);
596
597 short ethType = bb.getShort();
598 if (ethType == TYPE_VLAN) {
599 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
600 final short tci = bb.getShort();
601 eth.setPriorityCode((byte) (tci >> 13 & 0x07));
602 eth.setVlanID((short) (tci & 0x0fff));
603 ethType = bb.getShort();
604 } else {
605 eth.setVlanID(Ethernet.VLAN_UNTAGGED);
606 }
607 eth.setEtherType(ethType);
608
609 IPacket payload;
610 Deserializer<? extends IPacket> deserializer;
611 if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
612 deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
613 } else {
614 deserializer = Data.deserializer();
615 }
616 payload = deserializer.deserialize(data, bb.position(),
617 bb.limit() - bb.position());
618 payload.setParent(eth);
619 eth.setPayload(payload);
620
621 return eth;
622 };
623 }
624
alshabibc4901cd2014-09-05 16:50:40 -0700625}