package com.netifera.platform.net.wifi.packets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SuppressWarnings("boxing")
public class WiFiFramePrinter {
final private StringBuffer buffer = new StringBuffer();
// Information Element IDs
static final int IE_SSID =0x00;
static final int IE_SUPP_RATES =0x01;
static final int IE_FH_PARAMETER =0x02;
static final int IE_DS_PARAMETER =0x03;
static final int IE_CF_PARAMETER =0x04;
static final int IE_TIM =0x05;
static final int IE_IBSS_PARAMETER =0x06;
static final int IE_CHALLENGE_TEXT =0x10;
private static Map<Integer, String> mainTypeMap;
private static Map<Integer, String> typeMap;
private static Map<Integer, String> reasonMap;
private static Map<Integer, String> statusMap;
static {
mainTypeMap=new HashMap<Integer, String>();
mainTypeMap.put(WiFiFrame.MGT_FRAME, "Management Frame");
mainTypeMap.put(WiFiFrame.CONTROL_FRAME, "Control Frame");
mainTypeMap.put(WiFiFrame.DATA_FRAME, "Data Frame");
typeMap=new HashMap<Integer, String>();
typeMap.put(WiFiFrame.MGT_ASSOC_REQ, "Association Request");
typeMap.put(WiFiFrame.MGT_ASSOC_RESP, "Association Response");
typeMap.put(WiFiFrame.MGT_REASSOC_REQ, "Reassociation Request");
typeMap.put(WiFiFrame.MGT_REASSOC_RESP, "Reassociation Response");
typeMap.put(WiFiFrame.MGT_PROBE_REQ, "Probe Request");
typeMap.put(WiFiFrame.MGT_PROBE_RESP, "Probe Response");
typeMap.put(WiFiFrame.MGT_BEACON, "Beacon");
typeMap.put(WiFiFrame.MGT_ATIM, "ATIM");
typeMap.put(WiFiFrame.MGT_DISASS, "Dissassociate");
typeMap.put(WiFiFrame.MGT_AUTHENTICATION, "Authentication");
typeMap.put(WiFiFrame.MGT_DEAUTHENTICATION, "Deauthentication");
typeMap.put(WiFiFrame.CTRL_PS_POLL, "Power-Save poll");
typeMap.put(WiFiFrame.CTRL_RTS, "Request-to-send");
typeMap.put(WiFiFrame.CTRL_CTS, "Clear-to-send");
typeMap.put(WiFiFrame.CTRL_ACKNOWLEDGEMENT, "Acknowledgement");
typeMap.put(WiFiFrame.CTRL_CFP_END, "CF-End");
typeMap.put(WiFiFrame.CTRL_CFP_ENDACK, "CF-End + CF-Ack");
typeMap.put(WiFiFrame.DATA, "Data");
typeMap.put(WiFiFrame.DATA_CF_ACK, "Data + CF-Acknowledgement");
typeMap.put(WiFiFrame.DATA_CF_POLL, "Data + CF-Poll");
typeMap.put(WiFiFrame.DATA_CF_ACK_POLL, "Data + CF-Acknowledgement/Poll");
typeMap.put(WiFiFrame.DATA_NULL_FUNCTION, "Null");
typeMap.put(WiFiFrame.DATA_CF_ACK_NOD, "Data + Acknowledgement (No data)");
typeMap.put(WiFiFrame.DATA_CF_POLL_NOD, "Data + CF-Poll (No data)");
typeMap.put(WiFiFrame.DATA_CF_ACK_POLL_NOD, "Data + CF-Acknowledgement/Poll (No data)");
reasonMap=new HashMap<Integer, String>();
reasonMap.put(0x00, "Reserved");
reasonMap.put(0x01, "Unspecified reason");
reasonMap.put(0x02, "Previous authentication no longer valid");
reasonMap.put(0x03, "Deauthenticated because sending STA is leaving (has left) IBSS or ESS");
reasonMap.put(0x04, "Disassociated due to inactivity");
reasonMap.put(0x05, "Disassociated because AP is unable to handle all currently associated stations");
reasonMap.put(0x06, "Class 2 frame received from nonauthenticated station");
reasonMap.put(0x07, "Class 3 frame received from nonassociated station");
reasonMap.put(0x08, "Disassociated because sending STA is leaving (has left) BSS");
reasonMap.put(0x09, "Station requesting (re)association is not authenticated with responding station");
statusMap=new HashMap<Integer, String>();
statusMap.put(0x00, "Successful");
statusMap.put(0x01, "Unspecified failure");
statusMap.put(0x0A, "Cannot support all requested capabilities in the Capability information field");
statusMap.put(0x0B, "Reassociation denied due to inability to confirm that association exists");
statusMap.put(0x0C, "Association denied due to reason outside the scope of this standard");
statusMap.put(0x0D, "Responding station does not support the specified authentication algorithm");
statusMap.put(0x0E, "Received an Authentication frame with authentication sequence transaction sequence number out of expected sequence");
statusMap.put(0x0F, "Authentication rejected because of challenge failure");
statusMap.put(0x10, "Authentication rejected due to timeout waiting for next frame in sequence");
statusMap.put(0x11, "Association denied because AP is unable to handle additional associated stations");
statusMap.put(0x12, "Association denied due to requesting station not supporting all of the datarates in the BSSBasicServiceSet Parameter");
}
public void print(WiFiFrame frame) {
if (frame instanceof ManagementFrame) {
print((ManagementFrame) frame);
return;
}
if (frame instanceof DataFrame) {
print((DataFrame) frame);
return;
}
buffer.append("IEEE 802.11 " + typeMap.get(frame.type) + " " + frame.transmitter() + " -> " + frame.receiver());
printEncryptionStatus(frame);
}
public void print(DataFrame frame) {
buffer.append("IEEE 802.11 " + typeMap.get(frame.type) + " " + frame.source() + " -> " + frame.destination() + " via " + frame.bssid());
printEncryptionStatus(frame);
}
public void print(ManagementFrame frame) {
buffer.append("IEEE 802.11 " + typeMap.get(frame.type) + " " + frame.source() + " -> " + frame.destination() + " via " + frame.bssid());
printInformationElements(frame.informationElements());
printEncryptionStatus(frame);
}
public void print(AssociationResponse frame) {
print((ManagementFrame) frame);
printStatus(frame.statusCode);
}
public void print(Authentication frame) {
print((ManagementFrame) frame);
printStatus(frame.statusCode);
}
public void print(Deauthentication frame) {
print((ManagementFrame) frame);
printReason(frame.reasonCode);
}
public void print(Disassociation frame) {
print((ManagementFrame) frame);
printReason(frame.reasonCode);
}
private void printEncryptionStatus(WiFiFrame frame) {
if (frame.isProtected()) buffer.append(" PRIVATE");
}
private void printStatus(int code) {
buffer.append(" Status: "+statusMap.get(code));
}
private void printReason(int code) {
buffer.append(" Reason: "+reasonMap.get(code));
}
private void printInformationElements(List<InformationElement> elements) {
for (InformationElement element: elements) {
switch (element.id()) {
case IE_SSID:
buffer.append(" SSID=\"" + element.toString() + "\"");
break;
case IE_SUPP_RATES:
buffer.append(" Rates=");
byte[] IE = element.toBytes();
for(int j=0; j<IE.length; j++)
{
int rate=IE[j] & 0x7f;
if (j>0) buffer.append(",");
buffer.append((rate*500)/1000);
}
break;
case IE_FH_PARAMETER:
buffer.append(" FH="+hexa(element.toBytes()));
break;
case IE_DS_PARAMETER:
buffer.append(" Channel="+element.toInteger());
break;
case IE_CF_PARAMETER:
buffer.append(" CF="+hexa(element.toBytes()));
break;
case IE_TIM:
buffer.append(" TIM="+hexa(element.toBytes()));
break;
case IE_IBSS_PARAMETER:
buffer.append(" IBSS="+hexa(element.toBytes()));
break;
case IE_CHALLENGE_TEXT:
buffer.append(" Challenge=\""+element.toString()+"\"");
break;
default:
buffer.append(" "+element.id()+"="+hexa(element.toBytes()));
break;
}
}
}
// XXX
private String hexa(byte[] bytes) {
final String xlat = "0123456789abcdef";
String answer = "";
for (byte x: bytes) {
answer += String.valueOf(xlat.charAt((x >>> 4) & 0x0F)) + String.valueOf(xlat.charAt(x & 0x0F));
}
return answer;
}
public String toString() {
return buffer.toString();
}
}