Skip to content

Issue #110 - Probe Request Information Element Order change #116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: v1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
261 changes: 116 additions & 145 deletions pcap4j-core/src/main/java/org/pcap4j/packet/Dot11ProbeRequestPacket.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.pcap4j.util.ByteArrays;
Expand Down Expand Up @@ -474,20 +475,23 @@ public static final class Dot11ProbeRequestHeader extends Dot11ManagementHeader
*/
private static final long serialVersionUID = -2203820242563461514L;

private final Dot11SsidElement ssid;
private final Dot11SupportedRatesElement supportedRates;
private final Dot11RequestElement request;
private final Dot11ExtendedSupportedRatesElement extendedSupportedRates;
private final Dot11DsssParameterSetElement dsssParameterSet;
private final Dot11SupportedOperatingClassesElement supportedOperatingClasses;
private final Dot11HTCapabilitiesElement htCapabilities;
private final Dot112040BssCoexistenceElement twentyFortyBssCoexistence;
private final Dot11ExtendedCapabilitiesElement extendedCapabilities;
private final Dot11SsidListElement ssidList;
private final Dot11ChannelUsageElement channelUsage;
private final Dot11InterworkingElement interworking;
private final Dot11MeshIdElement meshId;
private final List<Dot11VendorSpecificElement> vendorSpecificElements;
private Dot11SsidElement ssid = null;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All fields should be final as possible.

private Dot11SupportedRatesElement supportedRates = null;
private Dot11RequestElement request = null;
private Dot11ExtendedSupportedRatesElement extendedSupportedRates = null;
private Dot11DsssParameterSetElement dsssParameterSet = null;
private Dot11SupportedOperatingClassesElement supportedOperatingClasses = null;
private Dot11HTCapabilitiesElement htCapabilities = null;
private Dot112040BssCoexistenceElement twentyFortyBssCoexistence = null;
private Dot11ExtendedCapabilitiesElement extendedCapabilities = null;
private Dot11SsidListElement ssidList = null;
private Dot11ChannelUsageElement channelUsage = null;
private Dot11InterworkingElement interworking = null;
private Dot11MeshIdElement meshId = null;
private List<Dot11VendorSpecificElement> vendorSpecificElements = new ArrayList<Dot11VendorSpecificElement>();

private List<Dot11InformationElement> infoElementOrderedList = new LinkedList<Dot11InformationElement>();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

infoElementOrderedList holds the same objects as the other fields such as meshId, which is a bad practice.

private static final short INFORMATION_ELEMENT_MAX_COUNT = 15;

private Dot11ProbeRequestHeader(
byte[] rawData, int offset, int length
Expand All @@ -497,137 +501,97 @@ private Dot11ProbeRequestHeader(
offset += mgmtHeaderLen;
length -= mgmtHeaderLen;

if (length > 0 && rawData[offset] == SSID.value().byteValue()) {
this.ssid = Dot11SsidElement.newInstance(rawData, offset, length);
int elemLen = ssid.length();
offset += elemLen;
length -= elemLen;
}
else {
this.ssid = null;
}
if (length > 0 && rawData[offset] == SUPPORTED_RATES.value().byteValue()) {
this.supportedRates = Dot11SupportedRatesElement.newInstance(rawData, offset, length);
int elemLen = supportedRates.length();
offset += elemLen;
length -= elemLen;
}
else {
this.supportedRates = null;
}
if (length > 0 && rawData[offset] == REQUEST.value().byteValue()) {
this.request = Dot11RequestElement.newInstance(rawData, offset, length);
int elemLen = request.length();
offset += elemLen;
length -= elemLen;
}
else {
this.request = null;
}
if (length > 0 && rawData[offset] == EXTENDED_SUPPORTED_RATES.value().byteValue()) {
this.extendedSupportedRates
= Dot11ExtendedSupportedRatesElement.newInstance(rawData, offset, length);
int elemLen = extendedSupportedRates.length();
offset += elemLen;
length -= elemLen;
}
else {
this.extendedSupportedRates = null;
}
if (length > 0 && rawData[offset] == DSSS_PARAMETER_SET.value().byteValue()) {
this.dsssParameterSet
= Dot11DsssParameterSetElement.newInstance(rawData, offset, length);
int elemLen = dsssParameterSet.length();
offset += elemLen;
length -= elemLen;
}
else {
this.dsssParameterSet = null;
}
if (length > 0 && rawData[offset] == SUPPORTED_OPERATING_CLASSES.value().byteValue()) {
this.supportedOperatingClasses
= Dot11SupportedOperatingClassesElement.newInstance(rawData, offset, length);
int elemLen = supportedOperatingClasses.length();
offset += elemLen;
length -= elemLen;
}
else {
this.supportedOperatingClasses = null;
}
if (length > 0 && rawData[offset] == HT_CAPABILITIES.value().byteValue()) {
this.htCapabilities = Dot11HTCapabilitiesElement.newInstance(rawData, offset, length);
int elemLen = htCapabilities.length();
offset += elemLen;
length -= elemLen;
}
else {
this.htCapabilities = null;
}
if (length > 0 && rawData[offset] == IE_20_40_BSS_COEXISTENCE.value().byteValue()) {
this.twentyFortyBssCoexistence
= Dot112040BssCoexistenceElement.newInstance(rawData, offset, length);
int elemLen = twentyFortyBssCoexistence.length();
offset += elemLen;
length -= elemLen;
}
else {
this.twentyFortyBssCoexistence = null;
}
if (length > 0 && rawData[offset] == EXTENDED_CAPABILITIES.value().byteValue()) {
this.extendedCapabilities
= Dot11ExtendedCapabilitiesElement.newInstance(rawData, offset, length);
int elemLen = extendedCapabilities.length();
offset += elemLen;
length -= elemLen;
}
else {
this.extendedCapabilities = null;
}
if (length > 0 && rawData[offset] == SSID_LIST.value().byteValue()) {
this.ssidList = Dot11SsidListElement.newInstance(rawData, offset, length);
int elemLen = ssidList.length();
offset += elemLen;
length -= elemLen;
}
else {
this.ssidList = null;
}
if (length > 0 && rawData[offset] == CHANNEL_USAGE.value().byteValue()) {
this.channelUsage = Dot11ChannelUsageElement.newInstance(rawData, offset, length);
int elemLen = channelUsage.length();
offset += elemLen;
length -= elemLen;
}
else {
this.channelUsage = null;
}
if (length > 0 && rawData[offset] == INTERWORKING.value().byteValue()) {
this.interworking = Dot11InterworkingElement.newInstance(rawData, offset, length);
int elemLen = interworking.length();
offset += elemLen;
length -= elemLen;
}
else {
this.interworking = null;
}
if (length > 0 && rawData[offset] == MESH_ID.value().byteValue()) {
this.meshId = Dot11MeshIdElement.newInstance(rawData, offset, length);
int elemLen = meshId.length();
offset += elemLen;
length -= elemLen;
}
else {
this.meshId = null;
}

this.vendorSpecificElements = new ArrayList<Dot11VendorSpecificElement>();
while (length > 0 && rawData[offset] == VENDOR_SPECIFIC.value().byteValue()) {
Dot11VendorSpecificElement elem
= Dot11VendorSpecificElement.newInstance(rawData, offset, length);
vendorSpecificElements.add(elem);
int elemLen = elem.length();
offset += elemLen;
length -= elemLen;
short iterCount = 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want the below code to be replaced with a packet factory like StaticIpV4OptionFactory for maintainability and enhanceability.

while (length > 4 && iterCount < INFORMATION_ELEMENT_MAX_COUNT) {
iterCount++;
if (length > 0 && rawData[offset] == SSID.value().byteValue()) {
this.ssid = Dot11SsidElement.newInstance(rawData, offset, length);
int elemLen = ssid.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.ssid);
}else if (length > 0 && rawData[offset] == SUPPORTED_RATES.value().byteValue()) {
this.supportedRates = Dot11SupportedRatesElement.newInstance(rawData, offset, length);
int elemLen = supportedRates.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.supportedRates);
}else if (length > 0 && rawData[offset] == REQUEST.value().byteValue()) {
this.request = Dot11RequestElement.newInstance(rawData, offset, length);
int elemLen = request.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.request);
}else if (length > 0 && rawData[offset] == EXTENDED_SUPPORTED_RATES.value().byteValue()) {
this.extendedSupportedRates = Dot11ExtendedSupportedRatesElement.newInstance(rawData, offset, length);
int elemLen = extendedSupportedRates.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.extendedSupportedRates);
}else if (length > 0 && rawData[offset] == DSSS_PARAMETER_SET.value().byteValue()) {
this.dsssParameterSet = Dot11DsssParameterSetElement.newInstance(rawData, offset, length);
int elemLen = dsssParameterSet.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.dsssParameterSet);
}else if (length > 0 && rawData[offset] == SUPPORTED_OPERATING_CLASSES.value().byteValue()) {
this.supportedOperatingClasses = Dot11SupportedOperatingClassesElement.newInstance(rawData, offset, length);
int elemLen = supportedOperatingClasses.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.supportedOperatingClasses);
}else if (length > 0 && rawData[offset] == HT_CAPABILITIES.value().byteValue()) {
this.htCapabilities = Dot11HTCapabilitiesElement.newInstance(rawData, offset, length);
int elemLen = htCapabilities.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.htCapabilities);
}else if (length > 0 && rawData[offset] == IE_20_40_BSS_COEXISTENCE.value().byteValue()) {
this.twentyFortyBssCoexistence = Dot112040BssCoexistenceElement.newInstance(rawData, offset, length);
int elemLen = twentyFortyBssCoexistence.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.twentyFortyBssCoexistence);
}else if (length > 0 && rawData[offset] == EXTENDED_CAPABILITIES.value().byteValue()) {
this.extendedCapabilities = Dot11ExtendedCapabilitiesElement.newInstance(rawData, offset, length);
int elemLen = extendedCapabilities.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.extendedCapabilities);
}else if (length > 0 && rawData[offset] == SSID_LIST.value().byteValue()) {
this.ssidList = Dot11SsidListElement.newInstance(rawData, offset, length);
int elemLen = ssidList.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.ssidList);
}else if (length > 0 && rawData[offset] == CHANNEL_USAGE.value().byteValue()) {
this.channelUsage = Dot11ChannelUsageElement.newInstance(rawData, offset, length);
int elemLen = channelUsage.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.channelUsage);
}else if (length > 0 && rawData[offset] == INTERWORKING.value().byteValue()) {
this.interworking = Dot11InterworkingElement.newInstance(rawData, offset, length);
int elemLen = interworking.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.interworking);
}else if (length > 0 && rawData[offset] == MESH_ID.value().byteValue()) {
this.meshId = Dot11MeshIdElement.newInstance(rawData, offset, length);
int elemLen = meshId.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(this.meshId);
}else {
while (length > 0 && rawData[offset] == VENDOR_SPECIFIC.value().byteValue()) {
Dot11VendorSpecificElement elem = Dot11VendorSpecificElement.newInstance(rawData, offset, length);
vendorSpecificElements.add(elem);
int elemLen = elem.length();
offset += elemLen;
length -= elemLen;
infoElementOrderedList.add(elem);
}
}
}
}

Expand Down Expand Up @@ -753,6 +717,13 @@ public List<Dot11VendorSpecificElement> getVendorSpecificElements() {
return new ArrayList<Dot11VendorSpecificElement>(vendorSpecificElements);
}

/**
* @return infoElementOrderedList
*/
public List<Dot11InformationElement> getInformationElementOrderedList() {
return infoElementOrderedList;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All fields must be immutable. So, here must make a defensive copy.

}

@Override
protected List<byte[]> getRawFields() {
List<byte[]> rawFields = super.getRawFields();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.pcap4j.packet.namednumber.Dot11InformationElementId;
import org.pcap4j.packet.namednumber.Dot11ServiceIntervalGranularity;
import org.pcap4j.packet.namednumber.Dot11VenueInfo;
import org.pcap4j.util.ByteArrays;
import org.pcap4j.util.MacAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -494,6 +495,61 @@ public void testNewPacket() {
}
}

@Test
public void testNewPacketUnOrdered(){
try {
//raw data bytes string for unordered probe request
String rawDataString = "40000000ffffffffffff984be157aaf7ffffffffffff30b100034f454e010802040b0c1216182403010b2d1a" +
"600100ff0000000100000000000000000000000000000000000032043048606cf2825146";
Integer fcsFromRawString = 1179747058;
byte[] rawData = ByteArrays.parseByteArray(rawDataString,"");
Dot11ProbeRequestPacket p
= Dot11ProbeRequestPacket.newPacket(rawData, 0, rawData.length);
assertEquals(p.getFcs(), fcsFromRawString);
}catch (IllegalRawDataException e) {
throw new AssertionError(e);
}
}

@Test
public void testNewPacketOrdered(){
try {
//raw data bytes string for ordered probe request
String rawDataString = "40000000ffffffffffffe4b318621f4cffffffffffff00140000010882840b168c92182432053048606cff" +
"2d1ae70917ffff0000000000000000000000000000000000000000008554ed06";
Integer fcsFromRawString = 116216965;
byte[] rawData = ByteArrays.parseByteArray(rawDataString,"");
Dot11ProbeRequestPacket p
= Dot11ProbeRequestPacket.newPacket(rawData, 0, rawData.length);

assertEquals(p.getFcs(), fcsFromRawString);
}catch (IllegalRawDataException e) {
throw new AssertionError(e);
}
}

@Test
public void testNewPacketInformationElementOrder(){
try {
//raw data bytes string for unordered probe request
String rawDataString = "40000000ffffffffffff984be157aaf7ffffffffffff30b100034f454e010802040b0c1216182403010b2d1a" +
"600100ff0000000100000000000000000000000000000000000032043048606cf2825146";

byte[] rawData = ByteArrays.parseByteArray(rawDataString,"");
Dot11ProbeRequestPacket p
= Dot11ProbeRequestPacket.newPacket(rawData, 0, rawData.length);
List<Dot11InformationElement> informationElementOrderedList = p.getHeader().getInformationElementOrderedList();

assertEquals(informationElementOrderedList.get(0).getElementId().name(),"SSID");
assertEquals(informationElementOrderedList.get(1).getElementId().name(),"Supported rates");
assertEquals(informationElementOrderedList.get(2).getElementId().name(),"DSSS Parameter Set");
assertEquals(informationElementOrderedList.get(3).getElementId().name(),"HT Capabilities");
assertEquals(informationElementOrderedList.get(4).getElementId().name(),"Extended Supported Rates");
}catch (IllegalRawDataException e) {
throw new AssertionError(e);
}
}

@Test
public void testGetHeader() {
Dot11ProbeRequestHeader h = packet.getHeader();
Expand Down