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