| /******************************************************************************* |
| * Copyright (c) 2014, 2019 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Vincent Perot - Initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.internal.pcap.core.protocol.ethernet2; |
| |
| import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
| |
| import java.nio.ByteBuffer; |
| import java.nio.ByteOrder; |
| import java.util.Arrays; |
| import java.util.Map; |
| import java.util.Objects; |
| |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.tracecompass.internal.pcap.core.packet.BadPacketException; |
| import org.eclipse.tracecompass.internal.pcap.core.packet.Packet; |
| import org.eclipse.tracecompass.internal.pcap.core.protocol.PcapProtocol; |
| import org.eclipse.tracecompass.internal.pcap.core.protocol.ipv4.IPv4Packet; |
| import org.eclipse.tracecompass.internal.pcap.core.protocol.unknown.UnknownPacket; |
| import org.eclipse.tracecompass.internal.pcap.core.trace.PcapFile; |
| import org.eclipse.tracecompass.internal.pcap.core.util.ConversionHelper; |
| import org.eclipse.tracecompass.internal.pcap.core.util.EthertypeHelper; |
| |
| import com.google.common.collect.ImmutableMap; |
| |
| /** |
| * Class that represents an Ethernet II packet. This should be called an |
| * Ethernet frame, but in order to keep the nomenclature consistent, this is |
| * called a packet. |
| * |
| * @author Vincent Perot |
| */ |
| public class EthernetIIPacket extends Packet { |
| |
| private final @Nullable Packet fChildPacket; |
| private final @Nullable ByteBuffer fPayload; |
| |
| /* We store MAC addresses as byte arrays since |
| * there is no standard java class to store them. */ |
| private final byte[] fSourceMacAddress; |
| private final byte[] fDestinationMacAddress; |
| |
| private final int fType; |
| |
| private @Nullable EthernetIIEndpoint fSourceEndpoint; |
| private @Nullable EthernetIIEndpoint fDestinationEndpoint; |
| |
| private @Nullable Map<String, String> fFields; |
| |
| /** |
| * Constructor of the Ethernet Packet class. |
| * |
| * @param file |
| * The file that contains this packet. |
| * @param parent |
| * The parent packet of this packet (the encapsulating packet). |
| * @param packet |
| * The entire packet (header and payload). |
| * @throws BadPacketException |
| * Thrown when the packet is erroneous. |
| */ |
| public EthernetIIPacket(PcapFile file, @Nullable Packet parent, ByteBuffer packet) throws BadPacketException { |
| super(file, parent, PcapProtocol.ETHERNET_II); |
| |
| if (packet.limit() <= EthernetIIValues.ETHERNET_II_MIN_SIZE) { |
| throw new BadPacketException("An Ethernet II packet can't be smaller than 14 bytes."); //$NON-NLS-1$ |
| } |
| |
| // The endpoints are lazy loaded. They are defined in the get*Endpoint() |
| // methods. |
| fSourceEndpoint = null; |
| fDestinationEndpoint = null; |
| |
| fFields = null; |
| |
| fDestinationMacAddress = new byte[EthernetIIValues.MAC_ADDRESS_SIZE]; |
| fSourceMacAddress = new byte[EthernetIIValues.MAC_ADDRESS_SIZE]; |
| packet.order(ByteOrder.BIG_ENDIAN); |
| packet.position(0); |
| packet.get(fDestinationMacAddress); |
| packet.get(fSourceMacAddress); |
| fType = ConversionHelper.unsignedShortToInt(packet.getShort()); |
| |
| // Get payload if it exists. |
| if (packet.remaining() > 0) { |
| ByteBuffer payload = packet.slice(); |
| payload.order(ByteOrder.BIG_ENDIAN); |
| fPayload = payload; |
| |
| } else { |
| fPayload = null; |
| } |
| |
| // Find child |
| fChildPacket = findChildPacket(); |
| |
| } |
| |
| @Override |
| public @Nullable Packet getChildPacket() { |
| return fChildPacket; |
| } |
| |
| @Override |
| public @Nullable ByteBuffer getPayload() { |
| return fPayload; |
| } |
| |
| /** |
| * Getter method for the source MAC Address. |
| * |
| * @return The source MAC address. |
| */ |
| public byte[] getSourceMacAddress() { |
| return checkNotNull(Arrays.copyOf(fSourceMacAddress, fSourceMacAddress.length)); |
| } |
| |
| /** |
| * Getter method for the destination MAC Address. |
| * |
| * @return The destination MAC address. |
| */ |
| public byte[] getDestinationMacAddress() { |
| return checkNotNull(Arrays.copyOf(fDestinationMacAddress, fDestinationMacAddress.length)); |
| } |
| |
| /** |
| * Getter method for Ethertype. See |
| * http://standards.ieee.org/develop/regauth/ethertype/eth.txt |
| * |
| * @return The Ethertype. This is used to determine the child packet.. |
| */ |
| public int getEthertype() { |
| return fType; |
| } |
| |
| @Override |
| protected @Nullable Packet findChildPacket() throws BadPacketException { |
| // TODO Add more protocols. |
| ByteBuffer payload = fPayload; |
| if (payload == null) { |
| return null; |
| } |
| switch (fType) { |
| case EthertypeHelper.ETHERTYPE_IPV4: |
| return new IPv4Packet(getPcapFile(), this, payload); |
| default: |
| return new UnknownPacket(getPcapFile(), this, payload); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| String string = getProtocol().getName() + ", Source: " + ConversionHelper.toMacAddress(fSourceMacAddress) + //$NON-NLS-1$ |
| ", Destination: " + ConversionHelper.toMacAddress(fDestinationMacAddress) + ", Type: " + //$NON-NLS-1$ //$NON-NLS-2$ |
| EthertypeHelper.toEtherType(fType) + "\n"; //$NON-NLS-1$ |
| final Packet child = fChildPacket; |
| if (child != null) { |
| return string + child.toString(); |
| } |
| return string; |
| } |
| |
| @Override |
| public boolean validate() { |
| // Not yet implemented. ATM, we consider that all packets are valid. |
| // This is the case for all packets. |
| // TODO Implement it. |
| return true; |
| } |
| |
| @Override |
| public EthernetIIEndpoint getSourceEndpoint() { |
| @Nullable EthernetIIEndpoint endpoint = fSourceEndpoint; |
| if (endpoint == null) { |
| endpoint = new EthernetIIEndpoint(this, true); |
| } |
| fSourceEndpoint = endpoint; |
| return fSourceEndpoint; |
| } |
| |
| @Override |
| public EthernetIIEndpoint getDestinationEndpoint() { |
| @Nullable EthernetIIEndpoint endpoint = fDestinationEndpoint; |
| |
| if (endpoint == null) { |
| endpoint = new EthernetIIEndpoint(this, false); |
| } |
| fDestinationEndpoint = endpoint; |
| return fDestinationEndpoint; |
| } |
| |
| @Override |
| public Map<String, String> getFields() { |
| Map<String, String> map = fFields; |
| if (map == null) { |
| ImmutableMap.Builder<String, String> builder = ImmutableMap.builder(); |
| builder.put("Source MAC Address", ConversionHelper.toMacAddress(fSourceMacAddress)); //$NON-NLS-1$ |
| builder.put("Destination MAC Address", ConversionHelper.toMacAddress(fDestinationMacAddress)); //$NON-NLS-1$ |
| builder.put("Ethertype", String.valueOf(EthertypeHelper.toEtherType(fType))); //$NON-NLS-1$ |
| |
| fFields = builder.build(); |
| return fFields; |
| } |
| return map; |
| } |
| |
| @Override |
| public String getLocalSummaryString() { |
| return "Src: " + ConversionHelper.toMacAddress(fSourceMacAddress) + " , Dst: " + ConversionHelper.toMacAddress(fDestinationMacAddress); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| @Override |
| protected String getSignificationString() { |
| return "Source MAC: " + ConversionHelper.toMacAddress(fSourceMacAddress) + " , Destination MAC: " + ConversionHelper.toMacAddress(fDestinationMacAddress); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| final Packet child = fChildPacket; |
| if (child != null) { |
| result = prime * result + child.hashCode(); |
| } else { |
| result = prime * result; |
| } |
| result = prime * result + Arrays.hashCode(fDestinationMacAddress); |
| if (child == null) { |
| result = prime * result + payloadHashCode(fPayload); |
| } |
| result = prime * result + Arrays.hashCode(fSourceMacAddress); |
| result = prime * result + fType; |
| return result; |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null) { |
| return false; |
| } |
| if (getClass() != obj.getClass()) { |
| return false; |
| } |
| EthernetIIPacket other = (EthernetIIPacket) obj; |
| if(!Objects.equals(fChildPacket, other.fChildPacket)) { |
| return false; |
| } |
| if (!Arrays.equals(fDestinationMacAddress, other.fDestinationMacAddress)) { |
| return false; |
| } |
| if (fChildPacket == null && !payloadEquals(fPayload, other.fPayload)) { |
| return false; |
| } |
| if (!Arrays.equals(fSourceMacAddress, other.fSourceMacAddress)) { |
| return false; |
| } |
| return (fType == other.fType); |
| } |
| |
| } |