Commit | Line | Data |
---|---|---|
5255c030 VP |
1 | /******************************************************************************* |
2 | * Copyright (c) 2014 Ericsson | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials are | |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | * | |
9 | * Contributors: | |
10 | * Vincent Perot - Initial API and implementation | |
11 | *******************************************************************************/ | |
12 | ||
71f2817f | 13 | package org.eclipse.tracecompass.internal.pcap.core.protocol.ethernet2; |
5255c030 | 14 | |
5db5a3a4 AM |
15 | import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
16 | ||
5255c030 VP |
17 | import java.nio.ByteBuffer; |
18 | import java.nio.ByteOrder; | |
19 | import java.util.Arrays; | |
20 | import java.util.Map; | |
21 | ||
5255c030 | 22 | import org.eclipse.jdt.annotation.Nullable; |
71f2817f AM |
23 | import org.eclipse.tracecompass.internal.pcap.core.packet.BadPacketException; |
24 | import org.eclipse.tracecompass.internal.pcap.core.packet.Packet; | |
25 | import org.eclipse.tracecompass.internal.pcap.core.protocol.PcapProtocol; | |
26 | import org.eclipse.tracecompass.internal.pcap.core.protocol.ipv4.IPv4Packet; | |
27 | import org.eclipse.tracecompass.internal.pcap.core.protocol.unknown.UnknownPacket; | |
28 | import org.eclipse.tracecompass.internal.pcap.core.trace.PcapFile; | |
29 | import org.eclipse.tracecompass.internal.pcap.core.util.ConversionHelper; | |
30 | import org.eclipse.tracecompass.internal.pcap.core.util.EthertypeHelper; | |
5255c030 VP |
31 | |
32 | import com.google.common.collect.ImmutableMap; | |
33 | ||
34 | /** | |
35 | * Class that represents an Ethernet II packet. This should be called an | |
36 | * Ethernet frame, but in order to keep the nomenclature consistent, this is | |
37 | * called a packet. | |
38 | * | |
39 | * @author Vincent Perot | |
40 | */ | |
41 | public class EthernetIIPacket extends Packet { | |
42 | ||
43 | private final @Nullable Packet fChildPacket; | |
44 | private final @Nullable ByteBuffer fPayload; | |
45 | ||
d6fca387 VP |
46 | /* We store MAC addresses as byte arrays since |
47 | * there is no standard java class to store them. */ | |
5255c030 VP |
48 | private final byte[] fSourceMacAddress; |
49 | private final byte[] fDestinationMacAddress; | |
d6fca387 | 50 | |
5255c030 VP |
51 | private final int fType; |
52 | ||
53 | private @Nullable EthernetIIEndpoint fSourceEndpoint; | |
54 | private @Nullable EthernetIIEndpoint fDestinationEndpoint; | |
55 | ||
5db5a3a4 | 56 | private @Nullable Map<String, String> fFields; |
5255c030 VP |
57 | |
58 | /** | |
59 | * Constructor of the Ethernet Packet class. | |
60 | * | |
61 | * @param file | |
62 | * The file that contains this packet. | |
63 | * @param parent | |
64 | * The parent packet of this packet (the encapsulating packet). | |
65 | * @param packet | |
66 | * The entire packet (header and payload). | |
67 | * @throws BadPacketException | |
68 | * Thrown when the packet is erroneous. | |
69 | */ | |
70 | public EthernetIIPacket(PcapFile file, @Nullable Packet parent, ByteBuffer packet) throws BadPacketException { | |
c88feda9 | 71 | super(file, parent, PcapProtocol.ETHERNET_II); |
5255c030 VP |
72 | |
73 | if (packet.array().length <= EthernetIIValues.ETHERNET_II_MIN_SIZE) { | |
74 | throw new BadPacketException("An Ethernet II packet can't be smaller than 14 bytes."); //$NON-NLS-1$ | |
75 | } | |
76 | ||
77 | // The endpoints are lazy loaded. They are defined in the get*Endpoint() | |
78 | // methods. | |
79 | fSourceEndpoint = null; | |
80 | fDestinationEndpoint = null; | |
81 | ||
82 | fFields = null; | |
83 | ||
84 | fDestinationMacAddress = new byte[EthernetIIValues.MAC_ADDRESS_SIZE]; | |
85 | fSourceMacAddress = new byte[EthernetIIValues.MAC_ADDRESS_SIZE]; | |
86 | packet.order(ByteOrder.BIG_ENDIAN); | |
87 | packet.position(0); | |
88 | packet.get(fDestinationMacAddress); | |
89 | packet.get(fSourceMacAddress); | |
90 | fType = ConversionHelper.unsignedShortToInt(packet.getShort()); | |
91 | ||
92 | // Get payload if it exists. | |
93 | if (packet.array().length - packet.position() > 0) { | |
94 | byte[] array = new byte[packet.array().length - packet.position()]; | |
95 | packet.get(array); | |
96 | ByteBuffer payload = ByteBuffer.wrap(array); | |
97 | if (payload != null) { | |
98 | payload.order(ByteOrder.BIG_ENDIAN); | |
99 | payload.position(0); | |
100 | } | |
101 | fPayload = payload; | |
102 | ||
103 | } else { | |
104 | fPayload = null; | |
105 | } | |
106 | ||
107 | // Find child | |
108 | fChildPacket = findChildPacket(); | |
109 | ||
110 | } | |
111 | ||
112 | @Override | |
113 | public @Nullable Packet getChildPacket() { | |
114 | return fChildPacket; | |
115 | } | |
116 | ||
117 | @Override | |
118 | public @Nullable ByteBuffer getPayload() { | |
119 | return fPayload; | |
120 | } | |
121 | ||
122 | /** | |
123 | * Getter method for the source MAC Address. | |
124 | * | |
125 | * @return The source MAC address. | |
126 | */ | |
127 | public byte[] getSourceMacAddress() { | |
5db5a3a4 | 128 | return checkNotNull(Arrays.copyOf(fSourceMacAddress, fSourceMacAddress.length)); |
5255c030 VP |
129 | } |
130 | ||
131 | /** | |
132 | * Getter method for the destination MAC Address. | |
133 | * | |
134 | * @return The destination MAC address. | |
135 | */ | |
136 | public byte[] getDestinationMacAddress() { | |
5db5a3a4 | 137 | return checkNotNull(Arrays.copyOf(fDestinationMacAddress, fDestinationMacAddress.length)); |
5255c030 VP |
138 | } |
139 | ||
140 | /** | |
141 | * Getter method for Ethertype. See | |
142 | * http://standards.ieee.org/develop/regauth/ethertype/eth.txt | |
143 | * | |
144 | * @return The Ethertype. This is used to determine the child packet.. | |
145 | */ | |
146 | public int getEthertype() { | |
147 | return fType; | |
148 | } | |
149 | ||
150 | @Override | |
151 | protected @Nullable Packet findChildPacket() throws BadPacketException { | |
152 | // TODO Add more protocols. | |
153 | ByteBuffer payload = fPayload; | |
154 | if (payload == null) { | |
155 | return null; | |
156 | } | |
157 | switch (fType) { | |
158 | case EthertypeHelper.ETHERTYPE_IPV4: | |
159 | return new IPv4Packet(getPcapFile(), this, payload); | |
160 | default: | |
161 | return new UnknownPacket(getPcapFile(), this, payload); | |
162 | } | |
163 | } | |
164 | ||
165 | @Override | |
166 | public String toString() { | |
167 | String string = getProtocol().getName() + ", Source: " + ConversionHelper.toMacAddress(fSourceMacAddress) + //$NON-NLS-1$ | |
168 | ", Destination: " + ConversionHelper.toMacAddress(fDestinationMacAddress) + ", Type: " + //$NON-NLS-1$ //$NON-NLS-2$ | |
169 | EthertypeHelper.toEtherType(fType) + "\n"; //$NON-NLS-1$ | |
170 | final Packet child = fChildPacket; | |
171 | if (child != null) { | |
172 | return string + child.toString(); | |
173 | } | |
174 | return string; | |
175 | } | |
176 | ||
177 | @Override | |
178 | public boolean validate() { | |
179 | // Not yet implemented. ATM, we consider that all packets are valid. | |
180 | // This is the case for all packets. | |
181 | // TODO Implement it. | |
182 | return true; | |
183 | } | |
184 | ||
185 | @Override | |
186 | public EthernetIIEndpoint getSourceEndpoint() { | |
187 | @Nullable EthernetIIEndpoint endpoint = fSourceEndpoint; | |
188 | if (endpoint == null) { | |
189 | endpoint = new EthernetIIEndpoint(this, true); | |
190 | } | |
191 | fSourceEndpoint = endpoint; | |
192 | return fSourceEndpoint; | |
193 | } | |
194 | ||
195 | @Override | |
196 | public EthernetIIEndpoint getDestinationEndpoint() { | |
197 | @Nullable EthernetIIEndpoint endpoint = fDestinationEndpoint; | |
198 | ||
199 | if (endpoint == null) { | |
200 | endpoint = new EthernetIIEndpoint(this, false); | |
201 | } | |
202 | fDestinationEndpoint = endpoint; | |
203 | return fDestinationEndpoint; | |
204 | } | |
205 | ||
206 | @Override | |
207 | public Map<String, String> getFields() { | |
5db5a3a4 | 208 | Map<String, String> map = fFields; |
5255c030 | 209 | if (map == null) { |
5db5a3a4 AM |
210 | ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String> builder(); |
211 | builder.put("Source MAC Address", ConversionHelper.toMacAddress(fSourceMacAddress)); //$NON-NLS-1$ | |
212 | builder.put("Destination MAC Address", ConversionHelper.toMacAddress(fDestinationMacAddress)); //$NON-NLS-1$ | |
213 | builder.put("Ethertype", String.valueOf(EthertypeHelper.toEtherType(fType))); //$NON-NLS-1$ | |
214 | ||
215 | fFields = checkNotNull(builder.build()); | |
216 | return fFields; | |
5255c030 VP |
217 | } |
218 | return map; | |
219 | } | |
220 | ||
221 | @Override | |
222 | public String getLocalSummaryString() { | |
223 | return "Src: " + ConversionHelper.toMacAddress(fSourceMacAddress) + " , Dst: " + ConversionHelper.toMacAddress(fDestinationMacAddress); //$NON-NLS-1$ //$NON-NLS-2$ | |
224 | } | |
225 | ||
226 | @Override | |
227 | protected String getSignificationString() { | |
228 | return "Source MAC: " + ConversionHelper.toMacAddress(fSourceMacAddress) + " , Destination MAC: " + ConversionHelper.toMacAddress(fDestinationMacAddress); //$NON-NLS-1$ //$NON-NLS-2$ | |
229 | } | |
230 | ||
231 | @Override | |
232 | public int hashCode() { | |
233 | final int prime = 31; | |
234 | int result = 1; | |
235 | final Packet child = fChildPacket; | |
236 | if (child != null) { | |
237 | result = prime * result + child.hashCode(); | |
238 | } else { | |
239 | result = prime * result; | |
240 | } | |
241 | result = prime * result + Arrays.hashCode(fDestinationMacAddress); | |
242 | final ByteBuffer payload = fPayload; | |
243 | if (payload != null) { | |
244 | result = prime * result + payload.hashCode(); | |
245 | } else { | |
246 | result = prime * result; | |
247 | } | |
248 | result = prime * result + Arrays.hashCode(fSourceMacAddress); | |
249 | result = prime * result + fType; | |
250 | return result; | |
251 | } | |
252 | ||
253 | @Override | |
254 | public boolean equals(@Nullable Object obj) { | |
255 | if (this == obj) { | |
256 | return true; | |
257 | } | |
258 | if (obj == null) { | |
259 | return false; | |
260 | } | |
261 | if (getClass() != obj.getClass()) { | |
262 | return false; | |
263 | } | |
264 | EthernetIIPacket other = (EthernetIIPacket) obj; | |
265 | if (fChildPacket == null) { | |
266 | if (other.fChildPacket != null) { | |
267 | return false; | |
268 | } | |
269 | } else { | |
270 | final Packet child = fChildPacket; | |
271 | if (child != null) { | |
272 | if (!child.equals(other.fChildPacket)) { | |
273 | return false; | |
274 | } | |
275 | } else { | |
276 | if (other.fChildPacket != null) { | |
277 | return false; | |
278 | } | |
279 | } | |
280 | } | |
281 | if (!Arrays.equals(fDestinationMacAddress, other.fDestinationMacAddress)) { | |
282 | return false; | |
283 | } | |
284 | if (fPayload == null) { | |
285 | if (other.fPayload != null) { | |
286 | return false; | |
287 | } | |
288 | } else { | |
289 | final ByteBuffer payload = fPayload; | |
290 | if (payload != null) { | |
291 | if (!payload.equals(other.fPayload)) { | |
292 | return false; | |
293 | } | |
294 | } else { | |
295 | if (other.fPayload != null) { | |
296 | return false; | |
297 | } | |
298 | } | |
299 | } | |
300 | if (!Arrays.equals(fSourceMacAddress, other.fSourceMacAddress)) { | |
301 | return false; | |
302 | } | |
303 | if (fType != other.fType) { | |
304 | return false; | |
305 | } | |
306 | return true; | |
307 | } | |
308 | ||
309 | } |