blob: 45468e38312ba91fc0aed4143a937e8339480160 [file] [log] [blame]
Deepa vaddireddy0060f532017-08-04 06:46:05 +00001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * 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
7 *
8 * 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.
15 */
16package org.opencord.dhcpl2relay.packet;
17
18import org.onlab.packet.ARP;
19import org.onlab.packet.BasePacket;
20import org.onlab.packet.DHCP;
21import org.onlab.packet.Data;
22import org.onlab.packet.DeserializationException;
23import org.onlab.packet.Deserializer;
24import org.onlab.packet.EthType;
25import org.onlab.packet.Ethernet;
26import org.onlab.packet.ICMP;
27import org.onlab.packet.ICMP6;
28import org.onlab.packet.IPacket;
29import org.onlab.packet.IPv4;
30import org.onlab.packet.IPv6;
31import org.onlab.packet.Ip6Address;
32import org.onlab.packet.LLC;
33import org.onlab.packet.LLDP;
34import org.onlab.packet.MacAddress;
35import org.onlab.packet.TCP;
36import org.onlab.packet.UDP;
37import org.onlab.packet.ndp.NeighborAdvertisement;
38import org.onlab.packet.ndp.NeighborSolicitation;
39import org.onlab.packet.ndp.Redirect;
40import org.onlab.packet.ndp.RouterAdvertisement;
41import org.onlab.packet.ndp.RouterSolicitation;
42
43import java.nio.ByteBuffer;
44import java.util.Arrays;
45import java.util.HashMap;
46import java.util.Map;
47
48import static com.google.common.base.Preconditions.checkNotNull;
49import static org.onlab.packet.PacketUtils.checkHeaderLength;
50import static org.onlab.packet.PacketUtils.checkInput;
51
52/**
53 * Ethernet Packet.
54 */
55public class DhcpEthernet extends BasePacket {
56 private static final String HEXES = "0123456789ABCDEF";
57 private static final String HEX_PROTO = "0x%s";
58
59 public static final short TYPE_ARP = EthType.EtherType.ARP.ethType().toShort();
60 public static final short TYPE_RARP = EthType.EtherType.RARP.ethType().toShort();
61 public static final short TYPE_IPV4 = EthType.EtherType.IPV4.ethType().toShort();
62 public static final short TYPE_IPV6 = EthType.EtherType.IPV6.ethType().toShort();
63 public static final short TYPE_LLDP = EthType.EtherType.LLDP.ethType().toShort();
64 public static final short TYPE_VLAN = EthType.EtherType.VLAN.ethType().toShort();
65 public static final short TYPE_QINQ = EthType.EtherType.QINQ.ethType().toShort();
66 public static final short TYPE_BSN = EthType.EtherType.BDDP.ethType().toShort();
67
68 public static final short MPLS_UNICAST = EthType.EtherType.MPLS_UNICAST.ethType().toShort();
69 public static final short MPLS_MULTICAST = EthType.EtherType.MPLS_MULTICAST.ethType().toShort();
70
71
72 public static final short VLAN_UNTAGGED = (short) 0xffff;
73
74 public static final short ETHERNET_HEADER_LENGTH = 14; // bytes
75 public static final short VLAN_HEADER_LENGTH = 4; // bytes
76
77 public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
78
79 private static final Map<Short, Deserializer<? extends IPacket>> ETHERTYPE_DESERIALIZER_MAP =
80 new HashMap<>();
81
82 static {
83 for (EthType.EtherType ethType : EthType.EtherType.values()) {
84 if (ethType.deserializer() != null) {
85 ETHERTYPE_DESERIALIZER_MAP.put(ethType.ethType().toShort(), ethType.deserializer());
86 }
87 }
88 }
89
90 protected MacAddress destinationMacAddress;
91 protected MacAddress sourceMacAddress;
92 protected byte priorityCode;
93 protected byte qInQPriorityCode;
94 protected short vlanID;
95 protected short qinqVid;
96 protected short qinqTPid;
97 protected short etherType;
98 protected boolean pad = false;
99
100 /**
101 * By default, set Ethernet to untagged.
102 */
103 public DhcpEthernet() {
104 super();
105 this.vlanID = org.onlab.packet.Ethernet.VLAN_UNTAGGED;
106 this.qinqVid = org.onlab.packet.Ethernet.VLAN_UNTAGGED;
107 this.qinqTPid = TYPE_QINQ;
108 }
109
110 public DhcpEthernet(org.onlab.packet.Ethernet eth) {
111 super();
112 this.destinationMacAddress = eth.getDestinationMAC();
113 this.sourceMacAddress = eth.getSourceMAC();
114 this.priorityCode = eth.getPriorityCode();
115 this.vlanID = eth.getVlanID();
116 this.etherType = eth.getEtherType();
117 this.pad = eth.isPad();
118 this.payload = eth.getPayload();
119 this.payload.setParent(this);
120 this.qinqVid = Ethernet.VLAN_UNTAGGED;
121 this.qinqTPid = TYPE_QINQ;
122 //this.parent = eth.getParent();
123 }
124
125
126 /**
127 * Gets the destination MAC address.
128 *
129 * @return the destination MAC as a byte array
130 */
131 public byte[] getDestinationMacAddress() {
132 return this.destinationMacAddress.toBytes();
133 }
134
135 /**
136 * Gets the destination MAC address.
137 *
138 * @return the destination MAC
139 */
140 public MacAddress getDestinationMac() {
141 return this.destinationMacAddress;
142 }
143
144 /**
145 * Sets the destination MAC address.
146 *
147 * @param destMac the destination MAC to set
148 * @return the Ethernet frame
149 */
150 public DhcpEthernet setDestinationMacAddress(final MacAddress destMac) {
151 this.destinationMacAddress = checkNotNull(destMac);
152 return this;
153 }
154
155 /**
156 * Sets the destination MAC address.
157 *
158 * @param destMac the destination MAC to set
159 * @return the Ethernet frame
160 */
161 public DhcpEthernet setDestinationMacAddress(final byte[] destMac) {
162 this.destinationMacAddress = MacAddress.valueOf(destMac);
163 return this;
164 }
165
166 /**
167 * Sets the destination MAC address.
168 *
169 * @param destMac the destination MAC to set
170 * @return the Ethernet frame
171 */
172 public DhcpEthernet setDestinationMacAddress(final String destMac) {
173 this.destinationMacAddress = MacAddress.valueOf(destMac);
174 return this;
175 }
176
177 /**
178 * Gets the source MAC address.
179 *
180 * @return the source MACAddress as a byte array
181 */
182 public byte[] getSourceMacAddress() {
183 return this.sourceMacAddress.toBytes();
184 }
185
186 /**
187 * Gets the source MAC address.
188 *
189 * @return the source MACAddress
190 */
191 public MacAddress getSourceMac() {
192 return this.sourceMacAddress;
193 }
194
195 /**
196 * Sets the source MAC address.
197 *
198 * @param sourceMac the source MAC to set
199 * @return the Ethernet frame
200 */
201 public DhcpEthernet setSourceMacAddress(final MacAddress sourceMac) {
202 this.sourceMacAddress = checkNotNull(sourceMac);
203 return this;
204 }
205
206 /**
207 * Sets the source MAC address.
208 *
209 * @param sourceMac the source MAC to set
210 * @return the Ethernet frame
211 */
212 public DhcpEthernet setSourceMacAddress(final byte[] sourceMac) {
213 this.sourceMacAddress = MacAddress.valueOf(sourceMac);
214 return this;
215 }
216
217 /**
218 * Sets the source MAC address.
219 *
220 * @param sourceMac the source MAC to set
221 * @return the Ethernet frame
222 */
223 public DhcpEthernet setSourceMacAddress(final String sourceMac) {
224 this.sourceMacAddress = MacAddress.valueOf(sourceMac);
225 return this;
226 }
227
228 /**
229 * Gets the priority code.
230 *
231 * @return the priorityCode
232 */
233 public byte getPriorityCode() {
234 return this.priorityCode;
235 }
236
237 /**
238 * Sets the priority code.
239 *
240 * @param priority the priorityCode to set
241 * @return the Ethernet frame
242 */
243 public DhcpEthernet setPriorityCode(final byte priority) {
244 this.priorityCode = priority;
245 return this;
246 }
247
248 /**
249 * Gets the QinQ priority code.
250 *
251 * @return the qInQPriorityCode
252 */
253 public byte getQinQPriorityCode() {
254 return this.qInQPriorityCode;
255 }
256
257 /**
258 * Sets the QinQ priority code.
259 *
260 * @param priority the priorityCode to set
261 * @return the Ethernet frame
262 */
263 public DhcpEthernet setQinQPriorityCode(final byte priority) {
264 this.qInQPriorityCode = priority;
265 return this;
266 }
267
268 /**
269 * Gets the VLAN ID.
270 *
271 * @return the vlanID
272 */
273 public short getVlanID() {
274 return this.vlanID;
275 }
276
277 /**
278 * Sets the VLAN ID.
279 *
280 * @param vlan the vlanID to set
281 * @return the Ethernet frame
282 */
283 public DhcpEthernet setVlanID(final short vlan) {
284 this.vlanID = vlan;
285 return this;
286 }
287
288 /**
289 * Gets the QinQ VLAN ID.
290 *
291 * @return the QinQ vlanID
292 */
293 public short getQinQVid() {
294 return this.qinqVid;
295 }
296
297 /**
298 * Sets the QinQ VLAN ID.
299 *
300 * @param vlan the vlanID to set
301 * @return the Ethernet frame
302 */
303 public DhcpEthernet setQinQVid(final short vlan) {
304 this.qinqVid = vlan;
305 return this;
306 }
307 /**
308 * Gets the QinQ TPID.
309 *
310 * @return the QinQ TPID
311 */
312 public short getQinQTPid() {
313 return this.qinqTPid;
314 }
315
316 /**
317 * Sets the QinQ TPID.
318 *
319 * @param tpId the TPID to set
320 * @return the Ethernet frame
321 */
322 public DhcpEthernet setQinQtpid(final short tpId) {
323 if (tpId != TYPE_VLAN && tpId != TYPE_QINQ) {
324 return null;
325 }
326 this.qinqTPid = tpId;
327 return this;
328 }
329 /**
330 * Gets the Ethernet type.
331 *
332 * @return the etherType
333 */
334 public short getEtherType() {
335 return this.etherType;
336 }
337
338 /**
339 * Sets the Ethernet type.
340 *
341 * @param ethType the etherType to set
342 * @return the Ethernet frame
343 */
344 public DhcpEthernet setEtherType(final short ethType) {
345 this.etherType = ethType;
346 return this;
347 }
348
349 /**
350 * @return True if the Ethernet frame is broadcast, false otherwise
351 */
352 public boolean isBroadcast() {
353 assert this.destinationMacAddress.length() == 6;
354 return this.destinationMacAddress.isBroadcast();
355 }
356
357 /**
358 * @return True is the Ethernet frame is multicast, False otherwise
359 */
360 public boolean isMulticast() {
361 return this.destinationMacAddress.isMulticast();
362 }
363
364 /**
365 * Pad this packet to 60 bytes minimum, filling with zeros?
366 *
367 * @return the pad
368 */
369 public boolean isPad() {
370 return this.pad;
371 }
372
373 /**
374 * Pad this packet to 60 bytes minimum, filling with zeros?
375 *
376 * @param pd
377 * the pad to set
378 * @return this
379 */
380 public DhcpEthernet setPad(final boolean pd) {
381 this.pad = pd;
382 return this;
383 }
384
385 @Override
386 public byte[] serialize() {
387 byte[] payloadData = null;
388 if (this.payload != null) {
389 this.payload.setParent(this);
390 payloadData = this.payload.serialize();
391 }
392 int length = 14 + (this.vlanID == org.onlab.packet.Ethernet.VLAN_UNTAGGED ? 0 : 4)
393 + (this.qinqVid == org.onlab.packet.Ethernet.VLAN_UNTAGGED ? 0 : 4)
394 + (payloadData == null ? 0 : payloadData.length);
395 if (this.pad && length < 60) {
396 length = 60;
397 }
398 final byte[] data = new byte[length];
399 final ByteBuffer bb = ByteBuffer.wrap(data);
400 bb.put(this.destinationMacAddress.toBytes());
401 bb.put(this.sourceMacAddress.toBytes());
402 if (this.qinqVid != org.onlab.packet.Ethernet.VLAN_UNTAGGED) {
403 bb.putShort(this.qinqTPid);
404 bb.putShort((short) (this.qInQPriorityCode << 13 | this.qinqVid & 0x0fff));
405 }
406 if (this.vlanID != org.onlab.packet.Ethernet.VLAN_UNTAGGED) {
407 bb.putShort(TYPE_VLAN);
408 bb.putShort((short) (this.priorityCode << 13 | this.vlanID & 0x0fff));
409 }
410 bb.putShort(this.etherType);
411 if (payloadData != null) {
412 bb.put(payloadData);
413 }
414 if (this.pad) {
415 Arrays.fill(data, bb.position(), data.length, (byte) 0x0);
416 }
417 return data;
418 }
419
420 @Override
421 public IPacket deserialize(final byte[] data, final int offset,
422 final int length) {
423 if (length <= 0) {
424 return null;
425 }
426 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
427 if (this.destinationMacAddress == null) {
428 this.destinationMacAddress = MacAddress.valueOf(new byte[6]);
429 }
430 final byte[] dstAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
431 bb.get(dstAddr);
432 this.destinationMacAddress = MacAddress.valueOf(dstAddr);
433
434 if (this.sourceMacAddress == null) {
435 this.sourceMacAddress = MacAddress.valueOf(new byte[6]);
436 }
437 final byte[] srcAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
438 bb.get(srcAddr);
439 this.sourceMacAddress = MacAddress.valueOf(srcAddr);
440
441 short ethType = bb.getShort();
442 if (ethType == TYPE_QINQ) {
443 final short tci = bb.getShort();
444 this.qInQPriorityCode = (byte) (tci >> 13 & 0x07);
445 this.qinqVid = (short) (tci & 0x0fff);
446 this.qinqTPid = TYPE_QINQ;
447 ethType = bb.getShort();
448 }
449
450 if (ethType == TYPE_VLAN) {
451 final short tci = bb.getShort();
452 this.priorityCode = (byte) (tci >> 13 & 0x07);
453 this.vlanID = (short) (tci & 0x0fff);
454 ethType = bb.getShort();
455
456 // there might be one more tag with 1q TPID
457 if (ethType == TYPE_VLAN) {
458 // packet is double tagged with 1q TPIDs
459 // We handle only double tagged packets here and assume that in this case
460 // TYPE_QINQ above was not hit
461 // We put the values retrieved above with TYPE_VLAN in
462 // qInQ fields
463 this.qInQPriorityCode = this.priorityCode;
464 this.qinqVid = this.vlanID;
465 this.qinqTPid = TYPE_VLAN;
466
467 final short innerTci = bb.getShort();
468 this.priorityCode = (byte) (innerTci >> 13 & 0x07);
469 this.vlanID = (short) (innerTci & 0x0fff);
470 ethType = bb.getShort();
471 }
472 } else {
473 this.vlanID = org.onlab.packet.Ethernet.VLAN_UNTAGGED;
474 }
475 this.etherType = ethType;
476
477 IPacket payload;
478 Deserializer<? extends IPacket> deserializer;
479 if (DhcpEthernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
480 deserializer = ETHERTYPE_DESERIALIZER_MAP.get(ethType);
481 } else {
482 deserializer = Data.deserializer();
483 }
484 try {
485 this.payload = deserializer.deserialize(data, bb.position(),
486 bb.limit() - bb.position());
487 this.payload.setParent(this);
488 } catch (DeserializationException e) {
489 return this;
490 }
491 return this;
492 }
493
494 /**
495 * Checks to see if a string is a valid MAC address.
496 *
497 * @param macAddress string to test if it is a valid MAC
498 * @return True if macAddress is a valid MAC, False otherwise
499 */
500 public static boolean isMacAddress(final String macAddress) {
501 final String[] macBytes = macAddress.split(":");
502 if (macBytes.length != 6) {
503 return false;
504 }
505 for (int i = 0; i < 6; ++i) {
506 if (DhcpEthernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1
507 || HEXES.indexOf(macBytes[i].toUpperCase().charAt(
508 1)) == -1) {
509 return false;
510 }
511 }
512 return true;
513 }
514
515 /**
516 * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
517 * matter, and returns a corresponding byte[].
518 *
519 * @param macAddress
520 * The MAC address to convert into a byte array
521 * @return The macAddress as a byte array
522 */
523 public static byte[] toMacAddress(final String macAddress) {
524 return MacAddress.valueOf(macAddress).toBytes();
525 }
526
527 /**
528 * Accepts a MAC address and returns the corresponding long, where the MAC
529 * bytes are set on the lower order bytes of the long.
530 *
531 * @param macAddress MAC address as a byte array
532 * @return a long containing the mac address bytes
533 */
534 public static long toLong(final byte[] macAddress) {
535 return MacAddress.valueOf(macAddress).toLong();
536 }
537
538 /**
539 * Converts a long MAC address to a byte array.
540 *
541 * @param macAddress MAC address set on the lower order bytes of the long
542 * @return the bytes of the mac address
543 */
544 public static byte[] toByteArray(final long macAddress) {
545 return MacAddress.valueOf(macAddress).toBytes();
546 }
547
548 /*
549 * (non-Javadoc)
550 *
551 * @see java.lang.Object#hashCode()
552 */
553 @Override
554 public int hashCode() {
555 final int prime = 7867;
556 int result = super.hashCode();
557 result = prime * result + this.destinationMacAddress.hashCode();
558 result = prime * result + this.etherType;
559 result = prime * result + this.qinqVid;
560 result = prime * result + this.qInQPriorityCode;
561 result = prime * result + this.vlanID;
562 result = prime * result + this.priorityCode;
563 result = prime * result + (this.pad ? 1231 : 1237);
564 result = prime * result + this.sourceMacAddress.hashCode();
565 return result;
566 }
567
568 /*
569 * (non-Javadoc)
570 *
571 * @see java.lang.Object#equals(java.lang.Object)
572 */
573 @Override
574 public boolean equals(final Object obj) {
575 if (this == obj) {
576 return true;
577 }
578 if (!super.equals(obj)) {
579 return false;
580 }
581 if (!(obj instanceof DhcpEthernet)) {
582 return false;
583 }
584 final DhcpEthernet other = (DhcpEthernet) obj;
585 if (!this.destinationMacAddress.equals(other.destinationMacAddress)) {
586 return false;
587 }
588 if (this.qInQPriorityCode != other.qInQPriorityCode) {
589 return false;
590 }
591 if (this.qinqVid != other.qinqVid) {
592 return false;
593 }
594 if (this.priorityCode != other.priorityCode) {
595 return false;
596 }
597 if (this.vlanID != other.vlanID) {
598 return false;
599 }
600 if (this.etherType != other.etherType) {
601 return false;
602 }
603 if (this.pad != other.pad) {
604 return false;
605 }
606 if (!this.sourceMacAddress.equals(other.sourceMacAddress)) {
607 return false;
608 }
609 return true;
610 }
611
612 /*
613 * (non-Javadoc)
614 *
615 * @see java.lang.Object#toString(java.lang.Object)
616 */
617 @Override
618 public String toString() {
619
620 final StringBuffer sb = new StringBuffer("\n");
621
622 final IPacket pkt = this.getPayload();
623
624 if (pkt instanceof ARP) {
625 sb.append("arp");
626 } else if (pkt instanceof LLDP) {
627 sb.append("lldp");
628 } else if (pkt instanceof ICMP) {
629 sb.append("icmp");
630 } else if (pkt instanceof IPv4) {
631 sb.append("ip");
632 } else if (pkt instanceof DHCP) {
633 sb.append("dhcp");
634 } else {
635 /*
636 * When we don't know the protocol, we print using
637 * the well known hex format instead of a decimal
638 * value.
639 */
640 sb.append(String.format(HEX_PROTO,
641 Integer.toHexString(this.getEtherType() & 0xffff)));
642 }
643
644 if (this.getQinQVid() != org.onlab.packet.Ethernet.VLAN_UNTAGGED) {
645 sb.append("\ndl_qinqVlan: ");
646 sb.append(this.getQinQVid());
647 sb.append("\ndl_qinqVlan_pcp: ");
648 sb.append(this.getQinQPriorityCode());
649 }
650
651 sb.append("\ndl_vlan: ");
652 if (this.getVlanID() == org.onlab.packet.Ethernet.VLAN_UNTAGGED) {
653 sb.append("untagged");
654 } else {
655 sb.append(this.getVlanID());
656 }
657 sb.append("\ndl_vlan_pcp: ");
658 sb.append(this.getPriorityCode());
659 sb.append("\ndl_src: ");
660 sb.append(bytesToHex(this.getSourceMacAddress()));
661 sb.append("\ndl_dst: ");
662 sb.append(bytesToHex(this.getDestinationMacAddress()));
663
664 if (pkt instanceof ARP) {
665 final ARP p = (ARP) pkt;
666 sb.append("\nnw_src: ");
667 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
668 .getSenderProtocolAddress())));
669 sb.append("\nnw_dst: ");
670 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
671 .getTargetProtocolAddress())));
672 } else if (pkt instanceof LLDP) {
673 sb.append("lldp packet");
674 } else if (pkt instanceof ICMP) {
675 final ICMP icmp = (ICMP) pkt;
676 sb.append("\nicmp_type: ");
677 sb.append(icmp.getIcmpType());
678 sb.append("\nicmp_code: ");
679 sb.append(icmp.getIcmpCode());
680 } else if (pkt instanceof IPv4) {
681 final IPv4 p = (IPv4) pkt;
682 sb.append("\nnw_src: ");
683 sb.append(IPv4.fromIPv4Address(p.getSourceAddress()));
684 sb.append("\nnw_dst: ");
685 sb.append(IPv4.fromIPv4Address(p.getDestinationAddress()));
686 sb.append("\nnw_tos: ");
687 sb.append(p.getDiffServ());
688 sb.append("\nnw_proto: ");
689 sb.append(p.getProtocol());
690
691 IPacket payload = pkt.getPayload();
692 if (payload != null) {
693 if (payload instanceof TCP) {
694 sb.append("\ntp_src: ");
695 sb.append(((TCP) payload).getSourcePort());
696 sb.append("\ntp_dst: ");
697 sb.append(((TCP) payload).getDestinationPort());
698
699 } else if (payload instanceof UDP) {
700 sb.append("\ntp_src: ");
701 sb.append(((UDP) payload).getSourcePort());
702 sb.append("\ntp_dst: ");
703 sb.append(((UDP) payload).getDestinationPort());
704 } else if (payload instanceof ICMP) {
705 final ICMP icmp = (ICMP) payload;
706 sb.append("\nicmp_type: ");
707 sb.append(icmp.getIcmpType());
708 sb.append("\nicmp_code: ");
709 sb.append(icmp.getIcmpCode());
710 }
711 }
712 } else if (pkt instanceof IPv6) {
713 final IPv6 ipv6 = (IPv6) pkt;
714 sb.append("\nipv6_src: ");
715 sb.append(Ip6Address.valueOf(ipv6.getSourceAddress()).toString());
716 sb.append("\nipv6_dst: ");
717 sb.append(Ip6Address.valueOf(ipv6.getDestinationAddress()).toString());
718 sb.append("\nipv6_proto: ");
719 sb.append(ipv6.getNextHeader());
720
721 IPacket payload = pkt.getPayload();
722 if (payload != null && payload instanceof ICMP6) {
723 final ICMP6 icmp6 = (ICMP6) payload;
724 sb.append("\nicmp6_type: ");
725 sb.append(icmp6.getIcmpType());
726 sb.append("\nicmp6_code: ");
727 sb.append(icmp6.getIcmpCode());
728
729 payload = payload.getPayload();
730 if (payload != null) {
731 if (payload instanceof NeighborSolicitation) {
732 final NeighborSolicitation ns = (NeighborSolicitation) payload;
733 sb.append("\nns_target_addr: ");
734 sb.append(Ip6Address.valueOf(ns.getTargetAddress()).toString());
735 ns.getOptions().forEach(option -> {
736 sb.append("\noption_type: ");
737 sb.append(option.type());
738 sb.append("\noption_data: ");
739 sb.append(bytesToHex(option.data()));
740 });
741 } else if (payload instanceof NeighborAdvertisement) {
742 final NeighborAdvertisement na = (NeighborAdvertisement) payload;
743 sb.append("\nna_target_addr: ");
744 sb.append(Ip6Address.valueOf(na.getTargetAddress()).toString());
745 sb.append("\nna_solicited_flag: ");
746 sb.append(na.getSolicitedFlag());
747 sb.append("\nna_router_flag: ");
748 sb.append(na.getRouterFlag());
749 sb.append("\nna_override_flag: ");
750 sb.append(na.getOverrideFlag());
751 na.getOptions().forEach(option -> {
752 sb.append("\noption_type: ");
753 sb.append(option.type());
754 sb.append("\noption_data: ");
755 sb.append(bytesToHex(option.data()));
756 });
757 } else if (payload instanceof RouterSolicitation) {
758 final RouterSolicitation rs = (RouterSolicitation) payload;
759 sb.append("\nrs");
760 rs.getOptions().forEach(option -> {
761 sb.append("\noption_type: ");
762 sb.append(option.type());
763 sb.append("\noption_data: ");
764 sb.append(bytesToHex(option.data()));
765 });
766 } else if (payload instanceof RouterAdvertisement) {
767 final RouterAdvertisement ra = (RouterAdvertisement) payload;
768 sb.append("\nra_hop_limit: ");
769 sb.append(ra.getCurrentHopLimit());
770 sb.append("\nra_mflag: ");
771 sb.append(ra.getMFlag());
772 sb.append("\nra_oflag: ");
773 sb.append(ra.getOFlag());
774 sb.append("\nra_reachable_time: ");
775 sb.append(ra.getReachableTime());
776 sb.append("\nra_retransmit_time: ");
777 sb.append(ra.getRetransmitTimer());
778 sb.append("\nra_router_lifetime: ");
779 sb.append(ra.getRouterLifetime());
780 ra.getOptions().forEach(option -> {
781 sb.append("\noption_type: ");
782 sb.append(option.type());
783 sb.append("\noption_data: ");
784 sb.append(bytesToHex(option.data()));
785 });
786 } else if (payload instanceof Redirect) {
787 final Redirect rd = (Redirect) payload;
788 sb.append("\nrd_target_addr: ");
789 sb.append(Ip6Address.valueOf(rd.getTargetAddress()).toString());
790 rd.getOptions().forEach(option -> {
791 sb.append("\noption_type: ");
792 sb.append(option.type());
793 sb.append("\noption_data: ");
794 sb.append(bytesToHex(option.data()));
795 });
796 }
797 }
798 }
799 } else if (pkt instanceof DHCP) {
800 sb.append("\ndhcp packet");
801 } else if (pkt instanceof Data) {
802 sb.append("\ndata packet");
803 } else if (pkt instanceof LLC) {
804 sb.append("\nllc packet");
805 } else {
806 sb.append("\nunknown packet");
807 }
808
809 return sb.toString();
810 }
811
812 public static String bytesToHex(byte[] in) {
813 final StringBuilder builder = new StringBuilder();
814 for (byte b : in) {
815 builder.append(String.format("%02x", b));
816 }
817 return builder.toString();
818 }
819
820 /**
821 * Deserializer function for Ethernet packets.
822 *
823 * @return deserializer function
824 */
825 public static Deserializer<DhcpEthernet> deserializer() {
826 return (data, offset, length) -> {
827 checkInput(data, offset, length, ETHERNET_HEADER_LENGTH);
828
829 byte[] addressBuffer = new byte[DATALAYER_ADDRESS_LENGTH];
830
831 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
832 DhcpEthernet eth = new DhcpEthernet();
833 // Read destination MAC address into buffer
834 bb.get(addressBuffer);
835 eth.setDestinationMacAddress(addressBuffer);
836
837 // Read source MAC address into buffer
838 bb.get(addressBuffer);
839 eth.setSourceMacAddress(addressBuffer);
840
841 short ethType = bb.getShort();
842 if (ethType == TYPE_QINQ) {
843 // in this case we excpect 2 VLAN headers
844 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH + VLAN_HEADER_LENGTH);
845 final short tci = bb.getShort();
846 eth.setQinQPriorityCode((byte) (tci >> 13 & 0x07));
847 eth.setQinQVid((short) (tci & 0x0fff));
848 eth.setQinQtpid(TYPE_QINQ);
849 ethType = bb.getShort();
850 }
851 if (ethType == TYPE_VLAN) {
852 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
853 final short tci = bb.getShort();
854 eth.setPriorityCode((byte) (tci >> 13 & 0x07));
855 eth.setVlanID((short) (tci & 0x0fff));
856 ethType = bb.getShort();
857
858 if (ethType == TYPE_VLAN) {
859 // We handle only double tagged packets here and assume that in this case
860 // TYPE_QINQ above was not hit
861 // We put the values retrieved above with TYPE_VLAN in
862 // qInQ fields
863 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
864 eth.setQinQPriorityCode(eth.getPriorityCode());
865 eth.setQinQVid(eth.getVlanID());
866 eth.setQinQtpid(TYPE_VLAN);
867
868 final short innerTci = bb.getShort();
869 eth.setPriorityCode((byte) (innerTci >> 13 & 0x07));
870 eth.setVlanID((short) (innerTci & 0x0fff));
871 ethType = bb.getShort();
872 }
873 } else {
874 eth.setVlanID(org.onlab.packet.Ethernet.VLAN_UNTAGGED);
875 }
876 eth.setEtherType(ethType);
877
878 IPacket payload;
879 Deserializer<? extends IPacket> deserializer;
880 if (DhcpEthernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
881 deserializer = DhcpEthernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
882 } else {
883 deserializer = Data.deserializer();
884 }
885 payload = deserializer.deserialize(data, bb.position(),
886 bb.limit() - bb.position());
887 payload.setParent(eth);
888 eth.setPayload(payload);
889
890 return eth;
891 };
892 }
893}