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.ipv4; | |
14 | ||
d6fca387 VP |
15 | import java.net.Inet4Address; |
16 | import java.net.InetAddress; | |
17 | import java.net.UnknownHostException; | |
5255c030 VP |
18 | import java.nio.ByteBuffer; |
19 | import java.nio.ByteOrder; | |
20 | import java.util.Arrays; | |
21 | import java.util.Map; | |
22 | ||
23 | import org.eclipse.jdt.annotation.NonNull; | |
24 | import org.eclipse.jdt.annotation.Nullable; | |
25 | import org.eclipse.linuxtools.pcap.core.packet.BadPacketException; | |
26 | import org.eclipse.linuxtools.pcap.core.packet.Packet; | |
27 | import org.eclipse.linuxtools.pcap.core.protocol.Protocol; | |
28 | import org.eclipse.linuxtools.pcap.core.protocol.tcp.TCPPacket; | |
29 | import org.eclipse.linuxtools.pcap.core.protocol.udp.UDPPacket; | |
30 | import org.eclipse.linuxtools.pcap.core.protocol.unknown.UnknownPacket; | |
31 | import org.eclipse.linuxtools.pcap.core.trace.PcapFile; | |
32 | import org.eclipse.linuxtools.pcap.core.util.ConversionHelper; | |
33 | import org.eclipse.linuxtools.pcap.core.util.IPProtocolNumberHelper; | |
34 | ||
35 | import com.google.common.collect.ImmutableMap; | |
36 | import com.google.common.collect.ImmutableMap.Builder; | |
37 | ||
38 | /** | |
39 | * Class that represents an Ethernet II packet. | |
40 | * | |
41 | * @author Vincent Perot | |
42 | */ | |
43 | public class IPv4Packet extends Packet { | |
44 | ||
45 | private final @Nullable Packet fChildPacket; | |
46 | private final @Nullable ByteBuffer fPayload; | |
47 | ||
48 | private final int fVersion; | |
49 | private final int fInternetHeaderLength; // in 4 bytes blocks | |
50 | private final int fDSCP; | |
51 | private final int fExplicitCongestionNotification; | |
52 | private final int fTotalLength; // in bytes | |
53 | private final int fIdentification; | |
54 | private final boolean fReservedFlag; | |
55 | private final boolean fDontFragmentFlag; | |
56 | private final boolean fMoreFragmentFlag; | |
57 | private final int fFragmentOffset; | |
58 | private final int fTimeToLive; | |
59 | private final int fIpDatagramProtocol; | |
60 | private final int fHeaderChecksum; | |
d6fca387 VP |
61 | private final Inet4Address fSourceIpAddress; |
62 | private final Inet4Address fDestinationIpAddress; | |
5255c030 VP |
63 | private final @Nullable byte[] fOptions; |
64 | ||
65 | private @Nullable IPv4Endpoint fSourceEndpoint; | |
66 | private @Nullable IPv4Endpoint fDestinationEndpoint; | |
67 | ||
68 | private @Nullable ImmutableMap<String, String> fFields; | |
69 | ||
70 | // TODO Interpret options. See | |
71 | // http://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml | |
72 | ||
73 | /** | |
74 | * Constructor of the IPv4 Packet class. | |
75 | * | |
76 | * @param file | |
77 | * The file that contains this packet. | |
78 | * @param parent | |
79 | * The parent packet of this packet (the encapsulating packet). | |
80 | * @param packet | |
81 | * The entire packet (header and payload). | |
82 | * @throws BadPacketException | |
83 | * Thrown when the packet is erroneous. | |
84 | */ | |
85 | public IPv4Packet(PcapFile file, @Nullable Packet parent, ByteBuffer packet) throws BadPacketException { | |
86 | super(file, parent, Protocol.IPV4); | |
87 | ||
88 | // The endpoints are lazy loaded. They are defined in the get*Endpoint() | |
89 | // methods. | |
90 | fSourceEndpoint = null; | |
91 | fDestinationEndpoint = null; | |
92 | ||
93 | fFields = null; | |
94 | ||
95 | packet.order(ByteOrder.BIG_ENDIAN); | |
96 | packet.position(0); | |
97 | ||
98 | byte storage = packet.get(); | |
99 | fVersion = ((storage & 0xF0) >> 4) & 0x000000FF; | |
100 | fInternetHeaderLength = storage & 0x0F; | |
101 | ||
102 | storage = packet.get(); | |
103 | fDSCP = ((storage & 0b11111100) >> 2) & 0x000000FF; | |
104 | fExplicitCongestionNotification = storage & 0b00000011; | |
105 | ||
106 | fTotalLength = ConversionHelper.unsignedShortToInt(packet.getShort()); | |
107 | fIdentification = ConversionHelper.unsignedShortToInt(packet.getShort()); | |
108 | ||
109 | storage = packet.get(); | |
110 | fReservedFlag = isBitSet(storage, 7); | |
111 | fDontFragmentFlag = isBitSet(storage, 6); | |
112 | fMoreFragmentFlag = isBitSet(storage, 5); | |
d6fca387 VP |
113 | int msb = ((storage & 0b00011111) << 8); |
114 | int lsb = ConversionHelper.unsignedByteToInt(packet.get()); | |
115 | fFragmentOffset = msb + lsb; | |
5255c030 VP |
116 | |
117 | fTimeToLive = ConversionHelper.unsignedByteToInt(packet.get()); | |
118 | fIpDatagramProtocol = ConversionHelper.unsignedByteToInt(packet.get()); | |
119 | fHeaderChecksum = ConversionHelper.unsignedShortToInt(packet.getShort()); | |
120 | ||
d6fca387 VP |
121 | byte[] source = new byte[IPv4Values.IP_ADDRESS_SIZE]; |
122 | byte[] destination = new byte[IPv4Values.IP_ADDRESS_SIZE]; | |
123 | packet.get(source); | |
124 | packet.get(destination); | |
125 | ||
126 | try { | |
127 | @SuppressWarnings("null") | |
128 | @NonNull Inet4Address sourceIP = (Inet4Address) InetAddress.getByAddress(source); | |
129 | @SuppressWarnings("null") | |
130 | @NonNull Inet4Address destinationIP = (Inet4Address) InetAddress.getByAddress(destination); | |
131 | fSourceIpAddress = sourceIP; | |
132 | fDestinationIpAddress = destinationIP; | |
133 | } catch (UnknownHostException e) { | |
134 | throw new BadPacketException("The IP Address size is not valid!"); //$NON-NLS-1$ | |
135 | } | |
5255c030 VP |
136 | |
137 | // Get options if there are any | |
138 | if (fInternetHeaderLength > IPv4Values.DEFAULT_HEADER_LENGTH) { | |
139 | fOptions = new byte[(fInternetHeaderLength - IPv4Values.DEFAULT_HEADER_LENGTH) * IPv4Values.BLOCK_SIZE]; | |
140 | packet.get(fOptions); | |
141 | } else { | |
142 | fOptions = null; | |
143 | } | |
144 | ||
145 | // Get payload if any. | |
146 | if (packet.array().length - packet.position() > 0) { | |
147 | byte[] array = new byte[packet.array().length - packet.position()]; | |
148 | packet.get(array); | |
149 | ByteBuffer payload = ByteBuffer.wrap(array); | |
150 | payload.order(ByteOrder.BIG_ENDIAN); | |
151 | payload.position(0); | |
152 | fPayload = payload; | |
153 | } else { | |
154 | fPayload = null; | |
155 | } | |
156 | ||
157 | // Find child | |
158 | fChildPacket = findChildPacket(); | |
159 | ||
160 | } | |
161 | ||
162 | @Override | |
163 | public @Nullable Packet getChildPacket() { | |
164 | return fChildPacket; | |
165 | } | |
166 | ||
167 | @Override | |
168 | public @Nullable ByteBuffer getPayload() { | |
169 | return fPayload; | |
170 | } | |
171 | ||
172 | /** | |
173 | * {@inheritDoc} | |
174 | * | |
175 | * See http://en.wikipedia.org/wiki/List_of_IP_protocol_numbers | |
176 | */ | |
177 | @Override | |
178 | protected @Nullable Packet findChildPacket() throws BadPacketException { | |
179 | // TODO Implement more protocols | |
180 | ByteBuffer payload = fPayload; | |
181 | if (payload == null) { | |
182 | return null; | |
183 | } | |
184 | ||
185 | switch (fIpDatagramProtocol) { | |
186 | case IPProtocolNumberHelper.PROTOCOL_NUMBER_TCP: | |
187 | return new TCPPacket(getPcapFile(), this, payload); | |
188 | case IPProtocolNumberHelper.PROTOCOL_NUMBER_UDP: | |
189 | return new UDPPacket(getPcapFile(), this, payload); | |
190 | default: | |
191 | return new UnknownPacket(getPcapFile(), this, payload); | |
192 | } | |
193 | ||
194 | } | |
195 | ||
196 | @Override | |
197 | public String toString() { | |
198 | // Generate flagString | |
199 | // This is very ugly. | |
200 | String flagString = null; | |
201 | ||
202 | if (fReservedFlag && fDontFragmentFlag && fMoreFragmentFlag) { // 111 | |
203 | flagString = "Flags: 0x07 (Invalid)"; //$NON-NLS-1$ | |
204 | } else if (fReservedFlag && fDontFragmentFlag && !fMoreFragmentFlag) { // 110 | |
205 | flagString = "Flags: 0x06 (Invalid)"; //$NON-NLS-1$ | |
206 | } else if (fReservedFlag && !fDontFragmentFlag && fMoreFragmentFlag) { // 101 | |
207 | flagString = "Flags: 0x05 (Invalid)"; //$NON-NLS-1$ | |
208 | } else if (fReservedFlag && !fDontFragmentFlag && !fMoreFragmentFlag) { // 100 | |
209 | flagString = "Flags: 0x04 (Invalid)"; //$NON-NLS-1$ | |
210 | } else if (!fReservedFlag && fDontFragmentFlag && fMoreFragmentFlag) { // 011 | |
211 | flagString = "Flags: 0x03 (Invalid)"; //$NON-NLS-1$ | |
212 | } else if (!fReservedFlag && fDontFragmentFlag && !fMoreFragmentFlag) { // 010 | |
213 | flagString = "Flags: 0x02 (Don't fragment)"; //$NON-NLS-1$ | |
214 | } else if (!fReservedFlag && !fDontFragmentFlag && fMoreFragmentFlag) { // 001 | |
215 | flagString = "Flags: 0x01 (More fragments)"; //$NON-NLS-1$ | |
216 | } else if (!fReservedFlag && !fDontFragmentFlag && !fMoreFragmentFlag) { // 000 | |
217 | flagString = "Flags: 0x00 (Don't have more fragments)"; //$NON-NLS-1$ | |
218 | } | |
219 | ||
220 | flagString += ", Fragment Offset: " + fFragmentOffset; //$NON-NLS-1$ | |
221 | ||
222 | // Generate checksum string | |
223 | // TODO calculate the expected checksum from packet | |
224 | String checksumString = "Header Checksum: " + String.format("%s%04x", "0x", fHeaderChecksum); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
225 | ||
d6fca387 | 226 | String string = getProtocol().getName() + ", Source: " + fSourceIpAddress.getHostAddress() + ", Destination: " + fDestinationIpAddress.getHostAddress() + //$NON-NLS-1$ //$NON-NLS-2$ |
5255c030 VP |
227 | "\nVersion: " + fVersion + ", Identification: " + String.format("%s%04x", "0x", fIdentification) + ", Header Length: " + getHeaderLength() + " bytes, Total Length: " + getTotalLength() + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ |
228 | " bytes\nDifferentiated Services Code Point: " + String.format("%s%02x", "0x", fDSCP) + "; Explicit Congestion Notification: " + String.format("%s%02x", "0x", fExplicitCongestionNotification) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ | |
229 | + "\n" + flagString + "\nTime to live: " + fTimeToLive + //$NON-NLS-1$ //$NON-NLS-2$ | |
230 | "\nProtocol: " + fIpDatagramProtocol + "\n" //$NON-NLS-1$ //$NON-NLS-2$ | |
231 | + checksumString + "\n"; //$NON-NLS-1$ | |
232 | final Packet child = fChildPacket; | |
233 | if (child != null) { | |
234 | return string + child.toString(); | |
235 | } | |
236 | return string; | |
237 | } | |
238 | ||
239 | /** | |
240 | * Getter method that returns the version of the IP protocol used. This | |
241 | * should always be set to 4 as IPv6 has its own class. | |
242 | * | |
243 | * @return The version of the IP used. | |
244 | */ | |
245 | public int getVersion() { | |
246 | return fVersion; | |
247 | } | |
248 | ||
249 | /** | |
250 | * Getter method that returns the header length in bytes. In the IPv4 | |
251 | * packet, this is specified in 4-bytes data block. By default, this method | |
252 | * returns 20 if there are no options present. Otherwise, it will return a | |
253 | * higher number. | |
254 | * | |
255 | * @return The header length in bytes. | |
256 | */ | |
257 | public int getHeaderLength() { | |
258 | return fInternetHeaderLength * IPv4Values.BLOCK_SIZE; | |
259 | } | |
260 | ||
261 | /** | |
262 | * Getter method that returns the Differentiated Services Code Point (a.k.a. | |
263 | * the Type of Service). This is useful for some technologies that require | |
264 | * real-time data exchange. | |
265 | * | |
266 | * @return The DSCP | |
267 | */ | |
268 | public int getDSCP() { | |
269 | return fDSCP; | |
270 | } | |
271 | ||
272 | /** | |
273 | * Getter method that returns the Explicit Congestion Notification (ECN). | |
274 | * This allows end-to-end communication without dropping packets. | |
275 | * | |
276 | * @return The ECN. | |
277 | */ | |
278 | public int getExplicitCongestionNotification() { | |
279 | return fExplicitCongestionNotification; | |
280 | } | |
281 | ||
282 | /** | |
283 | * Getter method to retrieve the length of the entire packet, in bytes. This | |
284 | * number is according to the packet, and might not be true if the packet is | |
285 | * erroneous. | |
286 | * | |
287 | * @return The total length (packet and payload) in bytes. | |
288 | */ | |
289 | public int getTotalLength() { | |
290 | return fTotalLength; | |
291 | } | |
292 | ||
293 | /** | |
294 | * Getter method to retrieve the Identification. This is a field that is | |
295 | * used to uniquely identify the packets, thus allowing the reconstruction | |
296 | * of fragmented IP packets. | |
297 | * | |
298 | * @return The packet identification. | |
299 | */ | |
300 | public int getIdentification() { | |
301 | return fIdentification; | |
302 | } | |
303 | ||
304 | /** | |
305 | * Getter method that returns the state of the Reserved flag. This must | |
306 | * always be zero. | |
307 | * | |
308 | * @return The state of the Reserved flag. | |
309 | */ | |
310 | public boolean getReservedFlag() { | |
311 | return fReservedFlag; | |
312 | } | |
313 | ||
314 | /** | |
315 | * Getter method that indicates if the packet can be fragmented or not. | |
316 | * | |
317 | * @return Whether the packet can be fragmented or not. | |
318 | */ | |
319 | public boolean getDontFragmentFlag() { | |
320 | return fDontFragmentFlag; | |
321 | } | |
322 | ||
323 | /** | |
324 | * Getter method that indicates if the packet has more fragments or not. | |
325 | * | |
326 | * @return Whether the packet has more fragments or not. | |
327 | */ | |
328 | public boolean getHasMoreFragment() { | |
329 | return fMoreFragmentFlag; | |
330 | } | |
331 | ||
332 | /** | |
333 | * Getter method that specify the offset of a particular fragment relative | |
334 | * to the original unfragmented packet, in 8-bytes blocks. * | |
335 | * | |
336 | * @return The fragment offset. | |
337 | */ | |
338 | public int getFragmentOffset() { | |
339 | return fFragmentOffset; | |
340 | } | |
341 | ||
342 | /** | |
343 | * Getter method that returns the time to live in seconds. In practice, this | |
344 | * is a hop count. This is used to prevent packets from persisting. | |
345 | * | |
346 | * @return The time left to live for the packet. | |
347 | */ | |
348 | public int getTimeToLive() { | |
349 | return fTimeToLive; | |
350 | } | |
351 | ||
352 | /** | |
353 | * Getter method that returns the encapsulated protocol. | |
354 | * | |
355 | * See http://en.wikipedia.org/wiki/List_of_IP_protocol_numbers | |
356 | * | |
357 | * @return The encapsulated protocol. | |
358 | */ | |
359 | public int getIpDatagramProtocol() { | |
360 | return fIpDatagramProtocol; | |
361 | } | |
362 | ||
363 | /** | |
364 | * Getter method that returns the checksum, according to the packet. This | |
365 | * checksum might be wrong if the packet is erroneous. | |
366 | * | |
367 | * @return The header checksum. | |
368 | */ | |
369 | public int getHeaderChecksum() { | |
370 | return fHeaderChecksum; | |
371 | } | |
372 | ||
373 | /** | |
374 | * Getter method that returns the source IP address. | |
375 | * | |
376 | * @return The source IP address, as a byte array in big-endian. | |
377 | */ | |
d6fca387 | 378 | public Inet4Address getSourceIpAddress() { |
5255c030 VP |
379 | return fSourceIpAddress; |
380 | } | |
381 | ||
382 | /** | |
383 | * Getter method that returns the destination IP address. | |
384 | * | |
385 | * @return The destination IP address, as a byte array in big-endian. | |
386 | */ | |
d6fca387 | 387 | public Inet4Address getDestinationIpAddress() { |
5255c030 VP |
388 | return fDestinationIpAddress; |
389 | } | |
390 | ||
391 | /** | |
392 | * Getter method that returns the options. This method returns null if no | |
393 | * options are present. | |
394 | * | |
395 | * @return The options of the packet. | |
396 | */ | |
397 | public @Nullable byte[] getOptions() { | |
398 | final byte[] options = fOptions; | |
399 | if (options == null) { | |
400 | return null; | |
401 | } | |
402 | return Arrays.copyOf(options, options.length); | |
403 | } | |
404 | ||
405 | @Override | |
406 | public boolean validate() { | |
407 | // Not yet implemented. ATM, we consider that all packets are valid. | |
408 | // This is the case for all packets. | |
409 | // TODO Implement it. | |
410 | return true; | |
411 | } | |
412 | ||
413 | @Override | |
414 | public IPv4Endpoint getSourceEndpoint() { | |
415 | @Nullable | |
416 | IPv4Endpoint endpoint = fSourceEndpoint; | |
417 | if (endpoint == null) { | |
418 | endpoint = new IPv4Endpoint(this, true); | |
419 | } | |
420 | fSourceEndpoint = endpoint; | |
421 | return fSourceEndpoint; | |
422 | } | |
423 | ||
424 | @Override | |
425 | public IPv4Endpoint getDestinationEndpoint() { | |
426 | @Nullable | |
427 | IPv4Endpoint endpoint = fDestinationEndpoint; | |
428 | ||
429 | if (endpoint == null) { | |
430 | endpoint = new IPv4Endpoint(this, false); | |
431 | } | |
432 | fDestinationEndpoint = endpoint; | |
433 | return fDestinationEndpoint; | |
434 | } | |
435 | ||
436 | @Override | |
437 | public Map<String, String> getFields() { | |
438 | ImmutableMap<String, String> map = fFields; | |
439 | if (map == null) { | |
440 | Builder<String, String> builder = ImmutableMap.<String, String> builder() | |
441 | .put("Version", String.valueOf(fVersion)) //$NON-NLS-1$ | |
442 | .put("Header Length", String.valueOf(getHeaderLength()) + " bytes") //$NON-NLS-1$ //$NON-NLS-2$ | |
443 | .put("Differentiated Services Field", String.format("%s%02x", "0x", fDSCP)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
444 | .put("Explicit Congestion Notification", String.format("%s%02x", "0x", fExplicitCongestionNotification)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
445 | .put("Total Length", String.valueOf(fTotalLength) + " bytes") //$NON-NLS-1$ //$NON-NLS-2$ | |
446 | .put("Identification", String.format("%s%04x", "0x", fIdentification)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
447 | .put("Don't Fragment Flag", String.valueOf(fDontFragmentFlag)) //$NON-NLS-1$ | |
448 | .put("More Fragment Flag", String.valueOf(fMoreFragmentFlag)) //$NON-NLS-1$ | |
449 | .put("Fragment Offset", String.valueOf(fFragmentOffset)) //$NON-NLS-1$ | |
450 | .put("Time to live", String.valueOf(fTimeToLive)) //$NON-NLS-1$ | |
451 | .put("Protocol", IPProtocolNumberHelper.toString(fIpDatagramProtocol) + " (" + String.valueOf(fIpDatagramProtocol) + ")") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
452 | .put("Checksum", String.format("%s%04x", "0x", fHeaderChecksum)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
d6fca387 VP |
453 | .put("Source IP Address", fSourceIpAddress.getHostAddress()) //$NON-NLS-1$ |
454 | .put("Destination IP Address", fDestinationIpAddress.getHostAddress()); //$NON-NLS-1$ | |
5255c030 VP |
455 | byte[] options = fOptions; |
456 | if (options == null) { | |
457 | builder.put("Options", EMPTY_STRING); //$NON-NLS-1$ | |
458 | } else { | |
459 | builder.put("Options", ConversionHelper.bytesToHex(options, true)); //$NON-NLS-1$ | |
460 | ||
461 | } | |
462 | @SuppressWarnings("null") | |
463 | @NonNull | |
464 | ImmutableMap<String, String> newMap = builder.build(); | |
465 | fFields = newMap; | |
466 | return newMap; | |
467 | } | |
468 | return map; | |
469 | } | |
470 | ||
471 | @Override | |
472 | public String getLocalSummaryString() { | |
d6fca387 | 473 | return "Src: " + fSourceIpAddress.getHostAddress() + " , Dst: " + fDestinationIpAddress.getHostAddress(); //$NON-NLS-1$ //$NON-NLS-2$ |
5255c030 VP |
474 | } |
475 | ||
476 | @Override | |
477 | protected String getSignificationString() { | |
478 | StringBuilder sb = new StringBuilder(); | |
d6fca387 | 479 | sb.append(fSourceIpAddress.getHostAddress()) |
5255c030 | 480 | .append(" > ") //$NON-NLS-1$ |
d6fca387 | 481 | .append(fDestinationIpAddress.getHostAddress()); |
5255c030 VP |
482 | |
483 | String flags = generateFlagString(); | |
484 | if (!(flags.equals(""))) { //$NON-NLS-1$ | |
485 | sb.append(' ') | |
486 | .append('[') | |
487 | .append(flags) | |
488 | .append(']'); | |
489 | } | |
490 | sb.append(" Id=") //$NON-NLS-1$ | |
491 | .append(fIdentification); | |
492 | ||
493 | final ByteBuffer payload = fPayload; | |
494 | if (payload != null) { | |
495 | sb.append(" Len=") //$NON-NLS-1$ | |
496 | .append(payload.array().length); | |
497 | } else { | |
498 | sb.append(" Len=0"); //$NON-NLS-1$ | |
499 | } | |
500 | String string = sb.toString(); | |
501 | if (string == null) { | |
502 | return EMPTY_STRING; | |
503 | } | |
504 | return string; | |
505 | } | |
506 | ||
507 | private String generateFlagString() { | |
508 | StringBuilder sb = new StringBuilder(); | |
509 | boolean start = true; | |
510 | ||
511 | if (fDontFragmentFlag) { | |
512 | if (!start) { | |
513 | sb.append(", "); //$NON-NLS-1$ | |
514 | } | |
515 | sb.append("DF"); //$NON-NLS-1$ | |
516 | start = false; | |
517 | } | |
518 | if (fMoreFragmentFlag) { | |
519 | if (!start) { | |
520 | sb.append(", "); //$NON-NLS-1$ | |
521 | } | |
522 | sb.append("MF"); //$NON-NLS-1$ | |
523 | start = false; | |
524 | } | |
525 | String string = sb.toString(); | |
526 | if (string == null) { | |
527 | return EMPTY_STRING; | |
528 | } | |
529 | return string; | |
530 | } | |
531 | ||
532 | @Override | |
533 | public int hashCode() { | |
534 | final int prime = 31; | |
535 | int result = 1; | |
536 | final Packet child = fChildPacket; | |
537 | if (child != null) { | |
538 | result = prime * result + child.hashCode(); | |
539 | } else { | |
540 | result = prime * result; | |
541 | } | |
542 | result = prime * result + fDSCP; | |
d6fca387 | 543 | result = prime * result + fDestinationIpAddress.hashCode(); |
5255c030 VP |
544 | result = prime * result + (fDontFragmentFlag ? 1231 : 1237); |
545 | result = prime * result + fExplicitCongestionNotification; | |
546 | result = prime * result + fFragmentOffset; | |
547 | result = prime * result + fHeaderChecksum; | |
548 | result = prime * result + fIdentification; | |
549 | result = prime * result + fInternetHeaderLength; | |
550 | result = prime * result + fIpDatagramProtocol; | |
551 | result = prime * result + (fMoreFragmentFlag ? 1231 : 1237); | |
552 | result = prime * result + Arrays.hashCode(fOptions); | |
553 | final ByteBuffer payload = fPayload; | |
554 | if (payload != null) { | |
555 | result = prime * result + payload.hashCode(); | |
556 | } else { | |
557 | result = prime * result; | |
558 | } | |
559 | result = prime * result + (fReservedFlag ? 1231 : 1237); | |
d6fca387 | 560 | result = prime * result + fSourceIpAddress.hashCode(); |
5255c030 VP |
561 | result = prime * result + fTimeToLive; |
562 | result = prime * result + fTotalLength; | |
563 | result = prime * result + fVersion; | |
564 | return result; | |
565 | } | |
566 | ||
567 | @Override | |
568 | public boolean equals(@Nullable Object obj) { | |
569 | if (this == obj) { | |
570 | return true; | |
571 | } | |
572 | if (obj == null) { | |
573 | return false; | |
574 | } | |
575 | if (getClass() != obj.getClass()) { | |
576 | return false; | |
577 | } | |
578 | IPv4Packet other = (IPv4Packet) obj; | |
579 | final Packet child = fChildPacket; | |
580 | if (child != null) { | |
581 | if (!child.equals(other.fChildPacket)) { | |
582 | return false; | |
583 | } | |
584 | } else { | |
585 | if (other.fChildPacket != null) { | |
586 | return false; | |
587 | } | |
588 | } | |
589 | ||
590 | if (fDSCP != other.fDSCP) { | |
591 | return false; | |
592 | } | |
d6fca387 | 593 | if (!(fDestinationIpAddress.equals(other.fDestinationIpAddress))) { |
5255c030 VP |
594 | return false; |
595 | } | |
596 | if (fDontFragmentFlag != other.fDontFragmentFlag) { | |
597 | return false; | |
598 | } | |
599 | if (fExplicitCongestionNotification != other.fExplicitCongestionNotification) { | |
600 | return false; | |
601 | } | |
602 | if (fFragmentOffset != other.fFragmentOffset) { | |
603 | return false; | |
604 | } | |
605 | if (fHeaderChecksum != other.fHeaderChecksum) { | |
606 | return false; | |
607 | } | |
608 | if (fIdentification != other.fIdentification) { | |
609 | return false; | |
610 | } | |
611 | if (fInternetHeaderLength != other.fInternetHeaderLength) { | |
612 | return false; | |
613 | } | |
614 | if (fIpDatagramProtocol != other.fIpDatagramProtocol) { | |
615 | return false; | |
616 | } | |
617 | if (fMoreFragmentFlag != other.fMoreFragmentFlag) { | |
618 | return false; | |
619 | } | |
620 | if (!Arrays.equals(fOptions, other.fOptions)) { | |
621 | return false; | |
622 | } | |
623 | final ByteBuffer payload = fPayload; | |
624 | if (payload != null) { | |
625 | if (!payload.equals(other.fPayload)) { | |
626 | return false; | |
627 | } | |
628 | } else { | |
629 | if (other.fPayload != null) { | |
630 | return false; | |
631 | } | |
632 | } | |
633 | if (fReservedFlag != other.fReservedFlag) { | |
634 | return false; | |
635 | } | |
d6fca387 | 636 | if (!(fSourceIpAddress.equals(other.fSourceIpAddress))) { |
5255c030 VP |
637 | return false; |
638 | } | |
639 | if (fTimeToLive != other.fTimeToLive) { | |
640 | return false; | |
641 | } | |
642 | if (fTotalLength != other.fTotalLength) { | |
643 | return false; | |
644 | } | |
645 | if (fVersion != other.fVersion) { | |
646 | return false; | |
647 | } | |
648 | return true; | |
649 | } | |
650 | ||
651 | } |