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