Merge pull request #763 from ejoerns/pull-req/cooja-analyzers

[Cooja] Fixes and enhancements for 6lowpan analyzers
This commit is contained in:
Fredrik Österlind 2014-08-06 08:55:29 +02:00
commit cb6cb3fc13
7 changed files with 1159 additions and 1002 deletions

View file

@ -27,7 +27,6 @@
* SUCH DAMAGE.
*
*/
package org.contikios.cooja.plugins;
import java.awt.BorderLayout;
@ -111,6 +110,7 @@ import org.contikios.cooja.util.StringUtils;
@ClassDescription("Radio messages")
@PluginType(PluginType.SIM_PLUGIN)
public class RadioLogger extends VisPlugin {
private static Logger logger = Logger.getLogger(RadioLogger.class);
private static final long serialVersionUID = -6927091711697081353L;
@ -141,7 +141,7 @@ public class RadioLogger extends VisPlugin {
private Observer radioMediumObserver;
private AbstractTableModel model;
private HashMap<String,Action> analyzerMap = new HashMap<String,Action>();
private HashMap<String, Action> analyzerMap = new HashMap<String, Action>();
private String analyzerName = null;
private ArrayList<PacketAnalyzer> analyzers = null;
private IEEE802154Analyzer analyzerWithPcap;
@ -187,6 +187,7 @@ public class RadioLogger extends VisPlugin {
private static final long serialVersionUID = 1692207305977527004L;
@Override
public String getColumnName(int col) {
if (col == COLUMN_TIME && formatTimeString) {
return "Time";
@ -194,14 +195,17 @@ public class RadioLogger extends VisPlugin {
return COLUMN_NAMES[col];
}
@Override
public int getRowCount() {
return connections.size();
}
@Override
public int getColumnCount() {
return COLUMN_NAMES.length;
}
@Override
public Object getValueAt(int row, int col) {
if (row < 0 || row >= connections.size()) {
return "";
@ -247,6 +251,7 @@ public class RadioLogger extends VisPlugin {
return null;
}
@Override
public boolean isCellEditable(int row, int col) {
if (col == COLUMN_FROM) {
/* Highlight source */
@ -265,6 +270,7 @@ public class RadioLogger extends VisPlugin {
return false;
}
@Override
public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
@ -274,6 +280,7 @@ public class RadioLogger extends VisPlugin {
private static final long serialVersionUID = -2199726885069809686L;
@Override
public String getToolTipText(MouseEvent e) {
java.awt.Point p = e.getPoint();
int rowIndex = rowAtPoint(p);
@ -290,14 +297,13 @@ public class RadioLogger extends VisPlugin {
/* TODO This entry may represent several hidden connections */
RadioConnectionLog conn = connections.get(modelRowIndex);
if (modelColumnIndex == COLUMN_TIME) {
return
"<html>" +
"Start time (us): " + conn.startTime +
"<br>" +
"End time (us): " + conn.endTime +
"<br><br>" +
"Duration (us): " + (conn.endTime - conn.startTime) +
"</html>";
return "<html>"
+ "Start time (us): " + conn.startTime
+ "<br>"
+ "End time (us): " + conn.endTime
+ "<br><br>"
+ "Duration (us): " + (conn.endTime - conn.startTime)
+ "</html>";
} else if (modelColumnIndex == COLUMN_FROM) {
return conn.connection.getSource().getMote().toString();
} else if (modelColumnIndex == COLUMN_TO) {
@ -329,6 +335,7 @@ public class RadioLogger extends VisPlugin {
/* Toggle time format */
dataTable.getTableHeader().addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int colIndex = dataTable.columnAtPoint(e.getPoint());
int columnIndex = dataTable.convertColumnIndexToModel(colIndex);
@ -343,11 +350,12 @@ public class RadioLogger extends VisPlugin {
});
dataTable.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
showInAllAction.actionPerformed(null);
} else if (e.getKeyCode() == KeyEvent.VK_F &&
(e.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
} else if (e.getKeyCode() == KeyEvent.VK_F
&& (e.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
searchField.setVisible(true);
searchField.requestFocus();
searchField.selectAll();
@ -367,6 +375,7 @@ public class RadioLogger extends VisPlugin {
dataTable.setRowSorter(logFilter);
dataTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
int row = dataTable.getSelectedRow();
if (row < 0) {
@ -395,11 +404,13 @@ public class RadioLogger extends VisPlugin {
payloadMenu.add(new JMenuItem(aliasAction));
payloadMenu.add(new JCheckBoxMenuItem(showDuplicatesAction) {
@Override
public boolean isSelected() {
return showDuplicates;
}
});
payloadMenu.add(new JCheckBoxMenuItem(hideNoDestinationAction) {
@Override
public boolean isSelected() {
return hideNoDestinationPackets;
}
@ -407,7 +418,6 @@ public class RadioLogger extends VisPlugin {
fileMenu.add(new JMenuItem(saveAction));
JPopupMenu popupMenu = new JPopupMenu();
JMenu focusMenu = new JMenu("Show in");
@ -418,7 +428,6 @@ public class RadioLogger extends VisPlugin {
popupMenu.add(focusMenu);
//a group of radio button menu items
ButtonGroup group = new ButtonGroup();
JRadioButtonMenuItem rbMenuItem = new JRadioButtonMenuItem(
createAnalyzerAction("No Analyzer", "none", null, true));
@ -436,15 +445,15 @@ public class RadioLogger extends VisPlugin {
analyzerMenu.add(rbMenuItem);
/* Load additional analyzers specified by projects (cooja.config) */
String[] projectAnalyzerSuites =
gui.getProjectConfig().getStringArrayValue(RadioLogger.class, "ANALYZERS");
String[] projectAnalyzerSuites
= gui.getProjectConfig().getStringArrayValue(RadioLogger.class, "ANALYZERS");
if (projectAnalyzerSuites != null) {
for (String suiteName: projectAnalyzerSuites) {
if (suiteName == null || suiteName.trim().isEmpty()) {
continue;
}
Class<? extends RadioLoggerAnalyzerSuite> suiteClass =
gui.tryLoadClass(RadioLogger.this, RadioLoggerAnalyzerSuite.class, suiteName);
Class<? extends RadioLoggerAnalyzerSuite> suiteClass
= gui.tryLoadClass(RadioLogger.this, RadioLoggerAnalyzerSuite.class, suiteName);
try {
RadioLoggerAnalyzerSuite suite = suiteClass.newInstance();
ArrayList<PacketAnalyzer> suiteAnalyzers = suite.getAnalyzers();
@ -472,6 +481,7 @@ public class RadioLogger extends VisPlugin {
/* Search text field */
searchField.setVisible(false);
searchField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
searchSelectNext(
@ -497,6 +507,7 @@ public class RadioLogger extends VisPlugin {
adjuster.packColumns();
radioMedium.addRadioMediumObserver(radioMediumObserver = new Observer() {
@Override
public void update(Observable obs, Object obj) {
RadioConnection conn = radioMedium.getLastConnection();
if (conn == null) {
@ -508,6 +519,7 @@ public class RadioLogger extends VisPlugin {
loggedConn.connection = conn;
loggedConn.packet = conn.getSource().getLastPacketTransmitted();
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
int lastSize = connections.size();
// Check if the last row is visible
@ -539,6 +551,7 @@ public class RadioLogger extends VisPlugin {
}
}
@Override
public void startPlugin() {
super.startPlugin();
rebuildAllEntries();
@ -560,18 +573,18 @@ public class RadioLogger extends VisPlugin {
}
int rows = dataTable.getModel().getRowCount();
for (int i=0; i < rows; i++) {
for (int i = 0; i < rows; i++) {
int r;
if (!reverse) {
r = (row + i + rows)%rows;
r = (row + i + rows) % rows;
} else {
r = (row - i + rows)%rows;
r = (row - i + rows) % rows;
}
String val = (String) dataTable.getModel().getValueAt(r, COLUMN_DATA);
if (!val.contains(text)) {
continue;
}
dataTable.setRowSelectionInterval(r,r);
dataTable.setRowSelectionInterval(r, r);
dataTable.scrollRectToVisible(dataTable.getCellRect(r, COLUMN_DATA, true));
searchField.setBackground(Color.WHITE);
return;
@ -586,11 +599,12 @@ public class RadioLogger extends VisPlugin {
*/
public void trySelectTime(final long time) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
if (dataTable.getRowCount() == 0) {
return;
}
for (int ai=0; ai < model.getRowCount(); ai++) {
for (int ai = 0; ai < model.getRowCount(); ai++) {
int index = dataTable.convertRowIndexToModel(ai);
if (connections.get(index).endTime < time) {
continue;
@ -600,14 +614,14 @@ public class RadioLogger extends VisPlugin {
dataTable.setRowSelectionInterval(ai, ai);
return;
}
dataTable.scrollRectToVisible(dataTable.getCellRect(dataTable.getRowCount()-1, 0, true));
dataTable.setRowSelectionInterval(dataTable.getRowCount()-1, dataTable.getRowCount()-1);
dataTable.scrollRectToVisible(dataTable.getCellRect(dataTable.getRowCount() - 1, 0, true));
dataTable.setRowSelectionInterval(dataTable.getRowCount() - 1, dataTable.getRowCount() - 1);
}
});
}
private void applyFilter() {
for(RadioConnectionLog conn: connections) {
for (RadioConnectionLog conn: connections) {
conn.data = null;
conn.tooltip = null;
conn.hides = 0;
@ -617,24 +631,25 @@ public class RadioLogger extends VisPlugin {
try {
logFilter.setRowFilter(null);
RowFilter<Object, Object> filter = new RowFilter<Object, Object>() {
@Override
public boolean include(RowFilter.Entry<? extends Object, ? extends Object> entry) {
int row = (Integer) entry.getIdentifier();
RadioConnectionLog current = connections.get(row);
byte[] currentData = current.packet.getPacketData();
if (!showDuplicates && row > 0) {
RadioConnectionLog previous = connections.get(row-1);
RadioConnectionLog previous = connections.get(row - 1);
byte[] previousData = previous.packet.getPacketData();
if (!showDuplicates &&
Arrays.equals(previousData, currentData) &&
previous.connection.getSource() == current.connection.getSource() &&
Arrays.equals(previous.connection.getAllDestinations(), current.connection.getAllDestinations())) {
if (connections.get(row-1).hiddenBy == null) {
connections.get(row-1).hides++;
connections.get(row).hiddenBy = connections.get(row-1);
if (!showDuplicates
&& Arrays.equals(previousData, currentData)
&& previous.connection.getSource() == current.connection.getSource()
&& Arrays.equals(previous.connection.getAllDestinations(), current.connection.getAllDestinations())) {
if (connections.get(row - 1).hiddenBy == null) {
connections.get(row - 1).hides++;
connections.get(row).hiddenBy = connections.get(row - 1);
} else {
connections.get(row-1).hiddenBy.hides++;
connections.get(row).hiddenBy = connections.get(row-1).hiddenBy;
connections.get(row - 1).hiddenBy.hides++;
connections.get(row).hiddenBy = connections.get(row - 1).hiddenBy;
}
return false;
}
@ -661,7 +676,7 @@ public class RadioLogger extends VisPlugin {
if (conn.packet == null) {
data = null;
} else if (conn.packet instanceof ConvertedRadioPacket) {
data = ((ConvertedRadioPacket)conn.packet).getOriginalPacketData();
data = ((ConvertedRadioPacket) conn.packet).getOriginalPacketData();
} else {
data = conn.packet.getPacketData();
}
@ -670,8 +685,8 @@ public class RadioLogger extends VisPlugin {
return;
}
StringBuffer brief = new StringBuffer();
StringBuffer verbose = new StringBuffer();
StringBuilder brief = new StringBuilder();
StringBuilder verbose = new StringBuilder();
/* default analyzer */
PacketAnalyzer.Packet packet = new PacketAnalyzer.Packet(data, PacketAnalyzer.MAC_LEVEL);
@ -698,7 +713,7 @@ public class RadioLogger extends VisPlugin {
}
}
private boolean analyzePacket(PacketAnalyzer.Packet packet, StringBuffer brief, StringBuffer verbose) {
private boolean analyzePacket(PacketAnalyzer.Packet packet, StringBuilder brief, StringBuilder verbose) {
if (analyzers == null) return false;
try {
boolean analyze = true;
@ -737,38 +752,40 @@ public class RadioLogger extends VisPlugin {
}
if (packet instanceof ConvertedRadioPacket && packet.getPacketData().length > 0) {
byte[] original = ((ConvertedRadioPacket)packet).getOriginalPacketData();
byte[] converted = ((ConvertedRadioPacket)packet).getPacketData();
conn.tooltip = "<html><font face=\"Monospaced\">" +
"<b>Packet data (" + original.length + " bytes)</b><br>" +
"<pre>" + StringUtils.hexDump(original) + "</pre>" +
"</font><font face=\"Monospaced\">" +
"<b>Cross-level packet data (" + converted.length + " bytes)</b><br>" +
"<pre>" + StringUtils.hexDump(converted) + "</pre>" +
"</font></html>";
byte[] original = ((ConvertedRadioPacket) packet).getOriginalPacketData();
byte[] converted = ((ConvertedRadioPacket) packet).getPacketData();
conn.tooltip = "<html><font face=\"Monospaced\">"
+ "<b>Packet data (" + original.length + " bytes)</b><br>"
+ "<pre>" + StringUtils.hexDump(original) + "</pre>"
+ "</font><font face=\"Monospaced\">"
+ "<b>Cross-level packet data (" + converted.length + " bytes)</b><br>"
+ "<pre>" + StringUtils.hexDump(converted) + "</pre>"
+ "</font></html>";
} else if (packet instanceof ConvertedRadioPacket) {
byte[] original = ((ConvertedRadioPacket)packet).getOriginalPacketData();
conn.tooltip = "<html><font face=\"Monospaced\">" +
"<b>Packet data (" + original.length + " bytes)</b><br>" +
"<pre>" + StringUtils.hexDump(original) + "</pre>" +
"</font><font face=\"Monospaced\">" +
"<b>No cross-level conversion available</b><br>" +
"</font></html>";
byte[] original = ((ConvertedRadioPacket) packet).getOriginalPacketData();
conn.tooltip = "<html><font face=\"Monospaced\">"
+ "<b>Packet data (" + original.length + " bytes)</b><br>"
+ "<pre>" + StringUtils.hexDump(original) + "</pre>"
+ "</font><font face=\"Monospaced\">"
+ "<b>No cross-level conversion available</b><br>"
+ "</font></html>";
} else {
byte[] data = packet.getPacketData();
conn.tooltip = "<html><font face=\"Monospaced\">" +
"<b>Packet data (" + data.length + " bytes)</b><br>" +
"<pre>" + StringUtils.hexDump(data) + "</pre>" +
"</font></html>";
conn.tooltip = "<html><font face=\"Monospaced\">"
+ "<b>Packet data (" + data.length + " bytes)</b><br>"
+ "<pre>" + StringUtils.hexDump(data) + "</pre>"
+ "</font></html>";
}
}
@Override
public void closePlugin() {
if (radioMediumObserver != null) {
radioMedium.deleteRadioMediumObserver(radioMediumObserver);
}
}
@Override
public Collection<Element> getConfigXML() {
ArrayList<Element> config = new ArrayList<Element>();
@ -796,7 +813,7 @@ public class RadioLogger extends VisPlugin {
}
if (aliases != null) {
for (Object key: aliases.keySet()) {
for (Object key : aliases.keySet()) {
element = new Element("alias");
element.setAttribute("payload", (String) key);
element.setAttribute("alias", (String) aliases.get(key));
@ -815,6 +832,7 @@ public class RadioLogger extends VisPlugin {
return config;
}
@Override
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
for (Element element : configXML) {
String name = element.getName();
@ -838,6 +856,7 @@ public class RadioLogger extends VisPlugin {
final Action action;
if (analyzerName != null && ((action = analyzerMap.get(analyzerName)) != null)) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
action.putValue(Action.SELECTED_KEY, Boolean.TRUE);
action.actionPerformed(null);
@ -853,6 +872,7 @@ public class RadioLogger extends VisPlugin {
}
private class RadioConnectionLog {
long startTime;
long endTime;
RadioConnection connection;
@ -864,15 +884,15 @@ public class RadioLogger extends VisPlugin {
String data = null;
String tooltip = null;
@Override
public String toString() {
if (data == null) {
RadioLogger.this.prepareDataString(this);
}
return
Long.toString(startTime / Simulation.MILLISECOND) + "\t" +
connection.getSource().getMote().getID() + "\t" +
getDestString(this) + "\t" +
data;
return Long.toString(startTime / Simulation.MILLISECOND) + "\t"
+ connection.getSource().getMote().getID() + "\t"
+ getDestString(this) + "\t"
+ data;
}
}
@ -888,7 +908,7 @@ public class RadioLogger extends VisPlugin {
for (Radio dest: dests) {
sb.append(dest.getMote().getID()).append(',');
}
sb.setLength(sb.length()-1);
sb.setLength(sb.length() - 1);
return sb.toString();
}
@ -909,6 +929,7 @@ public class RadioLogger extends VisPlugin {
Action action = new AbstractAction(name) {
private static final long serialVersionUID = -608913700422638454L;
@Override
public void actionPerformed(ActionEvent event) {
if (analyzers != analyzerList) {
analyzers = analyzerList;
@ -925,6 +946,7 @@ public class RadioLogger extends VisPlugin {
private Action clearAction = new AbstractAction("Clear") {
private static final long serialVersionUID = -6135583266684643117L;
@Override
public void actionPerformed(ActionEvent e) {
int size = connections.size();
if (size > 0) {
@ -938,6 +960,7 @@ public class RadioLogger extends VisPlugin {
private Action copyAction = new AbstractAction("Copy selected") {
private static final long serialVersionUID = 8412062977916108054L;
@Override
public void actionPerformed(ActionEvent e) {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
@ -957,11 +980,12 @@ public class RadioLogger extends VisPlugin {
private Action copyAllAction = new AbstractAction("Copy all") {
private static final long serialVersionUID = 1905586689441157304L;
@Override
public void actionPerformed(ActionEvent e) {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
StringBuilder sb = new StringBuilder();
for(int i=0; i < connections.size(); i++) {
for (int i = 0; i < connections.size(); i++) {
sb.append(connections.get(i).toString() + "\n");
}
@ -973,6 +997,7 @@ public class RadioLogger extends VisPlugin {
private Action saveAction = new AbstractAction("Save to file...") {
private static final long serialVersionUID = -3942984643211482179L;
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
int returnVal = fc.showSaveDialog(Cooja.getTopParentContainer());
@ -984,7 +1009,7 @@ public class RadioLogger extends VisPlugin {
if (saveFile.exists()) {
String s1 = "Overwrite";
String s2 = "Cancel";
Object[] options = { s1, s2 };
Object[] options = {s1, s2};
int n = JOptionPane.showOptionDialog(
Cooja.getTopParentContainer(),
"A file with the same name already exists.\nDo you want to remove it?",
@ -1002,7 +1027,7 @@ public class RadioLogger extends VisPlugin {
try {
PrintWriter outStream = new PrintWriter(new FileWriter(saveFile));
for(int i=0; i < connections.size(); i++) {
for (int i = 0; i < connections.size(); i++) {
outStream.print(connections.get(i).toString() + "\n");
}
outStream.close();
@ -1016,6 +1041,8 @@ public class RadioLogger extends VisPlugin {
private Action timeLineAction = new AbstractAction("Timeline") {
private static final long serialVersionUID = -4035633464748224192L;
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow = dataTable.getSelectedRow();
if (selectedRow < 0) return;
@ -1039,6 +1066,8 @@ public class RadioLogger extends VisPlugin {
private Action logListenerAction = new AbstractAction("Mote output") {
private static final long serialVersionUID = 1985006491187878651L;
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow = dataTable.getSelectedRow();
if (selectedRow < 0) return;
@ -1062,9 +1091,12 @@ public class RadioLogger extends VisPlugin {
private Action showInAllAction = new AbstractAction("Timeline and mote output") {
private static final long serialVersionUID = -3888292108886138128L;
{
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true));
}
@Override
public void actionPerformed(ActionEvent e) {
timeLineAction.actionPerformed(null);
logListenerAction.actionPerformed(null);
@ -1075,6 +1107,7 @@ public class RadioLogger extends VisPlugin {
private Action aliasAction = new AbstractAction("Payload alias...") {
private static final long serialVersionUID = -1678771087456128721L;
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow = dataTable.getSelectedRow();
if (selectedRow < 0) return;
@ -1088,9 +1121,9 @@ public class RadioLogger extends VisPlugin {
String alias = (String) JOptionPane.showInputDialog(
Cooja.getTopParentContainer(),
"Enter alias for all packets with identical payload.\n" +
"An empty string removes the current alias.\n\n" +
connections.get(selectedRow).data + "\n",
"Enter alias for all packets with identical payload.\n"
+ "An empty string removes the current alias.\n\n"
+ connections.get(selectedRow).data + "\n",
"Create packet payload alias",
JOptionPane.QUESTION_MESSAGE,
null,
@ -1126,6 +1159,7 @@ public class RadioLogger extends VisPlugin {
private boolean showDuplicates = false;
private AbstractAction showDuplicatesAction = new AbstractAction("Show duplicates") {
@Override
public void actionPerformed(ActionEvent e) {
showDuplicates = !showDuplicates;
rebuildAllEntries();
@ -1134,6 +1168,7 @@ public class RadioLogger extends VisPlugin {
private boolean hideNoDestinationPackets = false;
private AbstractAction hideNoDestinationAction = new AbstractAction("Hide airshots") {
@Override
public void actionPerformed(ActionEvent e) {
hideNoDestinationPackets = !hideNoDestinationPackets;
rebuildAllEntries();
@ -1143,14 +1178,14 @@ public class RadioLogger extends VisPlugin {
public String getConnectionsString() {
StringBuilder sb = new StringBuilder();
RadioConnectionLog[] cs = connections.toArray(new RadioConnectionLog[0]);
for(RadioConnectionLog c: cs) {
for (RadioConnectionLog c : cs) {
sb.append(c.toString() + "\n");
}
return sb.toString();
};
}
public void saveConnectionsToFile(String fileName) {
StringUtils.saveToFile(new File(fileName), getConnectionsString());
};
}
}

View file

@ -31,30 +31,38 @@ public class ICMPv6Analyzer extends PacketAnalyzer {
public static final int PREFIX_INFO = 3;
public static final int MTU_INFO = 5;
public static final String[] TYPE_NAME = new String[] {
"ECHO_REQUEST", "ECHO_REPLY",
"GROUP_QUERY", "GROUP_REPORT", "GROUP_REDUCTION",
"ROUTER_SOLICITATION", "ROUTER_ADVERTISEMENT",
"NEIGHBOR_SOLICITATION", "NEIGHBOR_ADVERTISEMENT", "REDIRECT",
"ROUTER RENUMBER", "NODE INFORMATION QUERY", "NODE INFORMATION RESPONSE"};
public static final String[] TYPE_NAME = new String[]{
"Echo Request", "Echo Reply",
"Group Query", "Group Report", "Group Reduction",
"Router Solicitation", "Router Advertisement",
"Neighbor Solicitation", "Neighbor Advertisement", "Redirect",
"Router Renumber", "Node Information Query", "Node Information Response"};
public static final String[] BRIEF_TYPE_NAME = new String[]{
"ECHO REQ", "ECHO RPLY",
"GRP QUERY", "GRP REPORT", "GRP REDUCTION",
"RS", "RA",
"NS", "NA", "REDIRECT",
"ROUTER RENUMBER", "NODE INFO QUERY", "NODE INFO RESP"};
public int analyzePacket(Packet packet, StringBuffer brief,
StringBuffer verbose) {
@Override
public int analyzePacket(Packet packet, StringBuilder brief,
StringBuilder verbose) {
int type = packet.get(0) & 0xff;
int code = packet.get(1) & 0xff;
// int checksum = ((packet.get(2) & 0xff) << 8) | packet.get(3) & 0xff;
brief.append("ICMPv6 ");
verbose.append("<b>ICMPv6</b>");
if (type >= 128 && (type - 128) < TYPE_NAME.length) {
brief.append(TYPE_NAME[type - 128]).append(' ').append(code);
verbose.append("Type: ").append(TYPE_NAME[type - 128]);
verbose.append(" Code:").append(code);
brief.append(BRIEF_TYPE_NAME[type - 128]).append(' ').append(code);
verbose.append("<br/>Type: ").append(TYPE_NAME[type - 128]);
verbose.append(", Code:").append(code);
} else if (type == 155) {
/* RPL */
brief.append("RPL ");
verbose.append("Type: RPL Code: ");
switch(code) {
verbose.append("<br/>Type: RPL Code: ");
switch (code) {
case RPL_CODE_DIS:
brief.append("DIS");
verbose.append("DIS");
@ -67,10 +75,13 @@ public class ICMPv6Analyzer extends PacketAnalyzer {
int version = packet.get(5) & 0xff;
int rank = ((packet.get(6) & 0xff) << 8) + (packet.get(7) & 0xff);
int mop = (packet.get(8) >> 3) & 0x07;
int dtsn = packet.get(9);
int dtsn = packet.get(9) & 0xFF;
verbose.append(" InstanceID: " + instanceID + " Version: " + version +
" Rank:" + rank + " MOP: " + mop + " DTSN: " + dtsn);
verbose.append(" InstanceID: ").append(instanceID)
.append(", Version: ").append(version)
.append(", Rank: ").append(rank)
.append(", MOP: ").append(mop)
.append(", DTSN: ").append(dtsn);
packet.consumeBytesStart(8);
break;

View file

@ -7,35 +7,36 @@ import org.contikios.cooja.util.StringUtils;
public class IEEE802154Analyzer extends PacketAnalyzer {
/* TODO: fix this to be correct */
// Addressing modes
public static final int NO_ADDRESS = 0;
public static final int RSV_ADDRESS = 1;
public static final int SHORT_ADDRESS = 2;
public static final int LONG_ADDRESS = 3;
// Frame types
public static final int BEACONFRAME = 0x00;
public static final int DATAFRAME = 0x01;
public static final int ACKFRAME = 0x02;
public static final int CMDFRAME = 0x03;
// private static final byte[] BROADCAST_ADDR = {(byte)0xff, (byte)0xff};
private static final String[] typeS = {"-", "D", "A"};
private static final String[] typeVerbose = {"BEACON", "DATA", "ACK"};
private static final String[] typeS = {"-", "D", "A", "C"};
private static final String[] typeVerbose = {"BEACON", "DATA", "ACK", "CMD"};
private static final String[] addrModeNames = {"None", "Reserved", "Short", "Long"};
private PcapExporter pcapExporter;
// private int defaultAddressMode = LONG_ADDRESS;
// private byte seqNo = 0;
// private int myPanID = 0xabcd;
public IEEE802154Analyzer(boolean pcap) {
if (pcap) try {
if (pcap) {
try {
pcapExporter = new PcapExporter();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void setPcapFile(File pcapFile) {
if (pcapExporter != null) {
@ -48,6 +49,7 @@ public class IEEE802154Analyzer extends PacketAnalyzer {
}
}
@Override
public boolean matchPacket(Packet packet) {
return packet.level == MAC_LEVEL;
}
@ -59,7 +61,9 @@ public class IEEE802154Analyzer extends PacketAnalyzer {
/* create a 802.15.4 packet of the bytes and "dispatch" to the
* next handler
*/
public int analyzePacket(Packet packet, StringBuffer brief, StringBuffer verbose) {
@Override
public int analyzePacket(Packet packet, StringBuilder brief, StringBuilder verbose) {
if (pcapExporter != null) {
try {
@ -71,15 +75,18 @@ public class IEEE802154Analyzer extends PacketAnalyzer {
}
int pos = packet.pos;
int type = packet.data[pos + 0] & 7;
// int security = (packet.data[pos + 0] >> 3) & 1;
// int pending = (packet.data[pos + 0] >> 4) & 1;
// int ackRequired = (packet.data[pos + 0] >> 5) & 1;
int panCompression = (packet.data[pos + 0]>> 6) & 1;
int destAddrMode = (packet.data[pos + 1] >> 2) & 3;
// int frameVersion = (packet.data[pos + 1] >> 4) & 3;
int srcAddrMode = (packet.data[pos + 1] >> 6) & 3;
// FCF field
int fcfType = packet.data[pos + 0] & 0x07;
boolean fcfSecurity = ((packet.data[pos + 0] >> 3) & 0x01) != 0;
boolean fcfPending = ((packet.data[pos + 0] >> 4) & 0x01) != 0;
boolean fcfAckRequested = ((packet.data[pos + 0] >> 5) & 0x01) != 0;
boolean fcfIntraPAN = ((packet.data[pos + 0] >> 6) & 0x01) != 0;
int fcfDestAddrMode = (packet.data[pos + 1] >> 2) & 0x03;
int fcfFrameVersion = (packet.data[pos + 1] >> 4) & 0x03;
int fcfSrcAddrMode = (packet.data[pos + 1] >> 6) & 0x03;
// Sequence number
int seqNumber = packet.data[pos + 2] & 0xff;
// Addressing Fields
int destPanID = 0;
int srcPanID = 0;
byte[] sourceAddress = null;
@ -87,15 +94,15 @@ public class IEEE802154Analyzer extends PacketAnalyzer {
pos += 3;
if (destAddrMode > 0) {
if (fcfDestAddrMode > 0) {
destPanID = (packet.data[pos] & 0xff) + ((packet.data[pos + 1] & 0xff) << 8);
pos += 2;
if (destAddrMode == SHORT_ADDRESS) {
if (fcfDestAddrMode == SHORT_ADDRESS) {
destAddress = new byte[2];
destAddress[1] = packet.data[pos];
destAddress[0] = packet.data[pos + 1];
pos += 2;
} else if (destAddrMode == LONG_ADDRESS) {
} else if (fcfDestAddrMode == LONG_ADDRESS) {
destAddress = new byte[8];
for (int i = 0; i < 8; i++) {
destAddress[i] = packet.data[pos + 7 - i];
@ -104,19 +111,19 @@ public class IEEE802154Analyzer extends PacketAnalyzer {
}
}
if (srcAddrMode > 0) {
if (panCompression == 0){
if (fcfSrcAddrMode > 0) {
if (fcfIntraPAN) {
srcPanID = destPanID;
} else {
srcPanID = (packet.data[pos] & 0xff) + ((packet.data[pos + 1] & 0xff) << 8);
pos += 2;
} else {
srcPanID = destPanID;
}
if (srcAddrMode == SHORT_ADDRESS) {
if (fcfSrcAddrMode == SHORT_ADDRESS) {
sourceAddress = new byte[2];
sourceAddress[1] = packet.data[pos];
sourceAddress[0] = packet.data[pos + 1];
pos += 2;
} else if (srcAddrMode == LONG_ADDRESS) {
} else if (fcfSrcAddrMode == LONG_ADDRESS) {
sourceAddress = new byte[8];
for (int i = 0; i < 8; i++) {
sourceAddress[i] = packet.data[pos + 7 - i];
@ -126,56 +133,80 @@ public class IEEE802154Analyzer extends PacketAnalyzer {
}
// int payloadLen = packet.data.length - pos;
brief.append("15.4 ");
brief.append(type < typeS.length ? typeS[type] : "?").append(' ');
brief.append(fcfType < typeS.length ? typeS[fcfType] : "?").append(' ');
verbose.append("<html><b>IEEE 802.15.4 ")
.append(type < typeVerbose.length ? typeVerbose[type] : "?")
.append(' ').append(seqNumber);
if (type != ACKFRAME) {
printAddress(brief, srcAddrMode, sourceAddress);
brief.append(' ');
printAddress(brief, destAddrMode, destAddress);
.append(fcfType < typeVerbose.length ? typeVerbose[fcfType] : "?")
.append("</b> #").append(seqNumber);
verbose.append("</b><br>From ");
if (fcfType != ACKFRAME) {
printAddress(brief, fcfSrcAddrMode, sourceAddress);
brief.append(' ');
printAddress(brief, fcfDestAddrMode, destAddress);
verbose.append("<br>From ");
if (srcPanID != 0) {
verbose.append(StringUtils.toHex((byte)(srcPanID >> 8)))
.append(StringUtils.toHex((byte)(srcPanID & 0xff)))
verbose.append("0x")
.append(StringUtils.toHex((byte) (srcPanID >> 8)))
.append(StringUtils.toHex((byte) (srcPanID & 0xff)))
.append('/');
}
printAddress(verbose, srcAddrMode, sourceAddress);
printAddress(verbose, fcfSrcAddrMode, sourceAddress);
verbose.append(" to ");
if (destPanID != 0) {
verbose.append(StringUtils.toHex((byte)(destPanID >> 8)))
.append(StringUtils.toHex((byte)(destPanID & 0xff)))
verbose.append("0x")
.append(StringUtils.toHex((byte) (destPanID >> 8)))
.append(StringUtils.toHex((byte) (destPanID & 0xff)))
.append('/');
}
printAddress(verbose, destAddrMode, destAddress);
} else {
printAddress(verbose, fcfDestAddrMode, destAddress);
}
verbose.append("<br/>Sec = ").append(fcfSecurity)
.append(", Pend = ").append(fcfPending)
.append(", ACK = ").append(fcfAckRequested)
.append(", iPAN = ").append(fcfIntraPAN)
.append(", DestAddr = ").append(addrModeNames[fcfDestAddrMode])
.append(", Vers. = ").append(fcfFrameVersion)
.append(", SrcAddr = ").append(addrModeNames[fcfSrcAddrMode]);
/* update packet */
packet.pos = pos;
/* remove CRC from the packet */
packet.consumeBytesEnd(2);
if (fcfType == ACKFRAME) {
/* got ack - no more to do ... */
return ANALYSIS_OK_FINAL;
}
/* update packet */
packet.pos = pos;
packet.level = NETWORK_LEVEL;
/* remove CRC from the packet */
packet.consumeBytesEnd(2);
packet.llsender = sourceAddress;
packet.llreceiver = destAddress;
return ANALYSIS_OK_CONTINUE;
}
private void printAddress(StringBuffer sb, int type, byte[] addr) {
private void printAddress(StringBuilder sb, int type, byte[] addr) {
if (type == SHORT_ADDRESS) {
sb.append(StringUtils.toHex(addr));
sb.append("0x").append(StringUtils.toHex(addr));
} else if (type == LONG_ADDRESS) {
sb.append(StringUtils.toHex(addr[0]) + StringUtils.toHex(addr[1]) + ":" +
StringUtils.toHex(addr[2]) + StringUtils.toHex(addr[3]) + ":" +
StringUtils.toHex(addr[4]) + StringUtils.toHex(addr[5]) + ":" +
StringUtils.toHex(addr[6]) + StringUtils.toHex(addr[7]));
sb.append(StringUtils.toHex(addr[0]))
.append(':')
.append(StringUtils.toHex(addr[1]))
.append(':')
.append(StringUtils.toHex(addr[2]))
.append(':')
.append(StringUtils.toHex(addr[3]))
.append(':')
.append(StringUtils.toHex(addr[4]))
.append(':')
.append(StringUtils.toHex(addr[5]))
.append(':')
.append(StringUtils.toHex(addr[6]))
.append(':')
.append(StringUtils.toHex(addr[7]));
}
}
}

View file

@ -4,14 +4,18 @@ import org.contikios.cooja.util.StringUtils;
public class IPHCPacketAnalyzer extends PacketAnalyzer {
public final static int SICSLOWPAN_UDP_PORT_MIN = 0xF0B0;
public final static int SICSLOWPAN_UDP_PORT_MAX = 0xF0BF; /* F0B0 + 15 */
public final static int SICSLOWPAN_UDP_4_BIT_PORT_MIN = 0xF0B0;
public final static int SICSLOWPAN_UDP_4_BIT_PORT_MAX = 0xF0BF; /* F0B0 + 15 */
public final static int SICSLOWPAN_UDP_8_BIT_PORT_MIN = 0xF000;
public final static int SICSLOWPAN_UDP_8_BIT_PORT_MAX = 0xF0FF; /* F000 + 255 */
public final static int SICSLOWPAN_DISPATCH_IPV6 = 0x41; /* 01000001 = 65 */
public final static int SICSLOWPAN_DISPATCH_HC1 = 0x42; /* 01000010 = 66 */
public final static int SICSLOWPAN_DISPATCH_IPHC = 0x60; /* 011xxxxx = ... */
public final static int SICSLOWPAN_DISPATCH_FRAG1 = 0xc0; /* 1100= 0xxx */
public final static int SICSLOWPAN_DISPATCH_FRAGN = 0xe0; /* 1110= 0xxx */
public final static int EXT_HDR_HOP_BY_HOP = 0;
public final static int EXT_HDR_ROUTING = 43;
public final static int EXT_HDR_FRAGMENT = 44;
/*
* Values of fields within the IPHC encoding first byte
@ -44,30 +48,33 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
private static final int SICSLOWPAN_NDC_UDP_MASK = 0xf8;
private static final int SICSLOWPAN_NHC_UDP_ID = 0xf0;
private static final int SICSLOWPAN_NHC_UDP_C = 0xf3;
private static final int SICSLOWPAN_NHC_UDP_I = 0xf0;
private static final int SICSLOWPAN_NHC_UDP_00 = 0xf0;
private static final int SICSLOWPAN_NHC_UDP_01 = 0xf1;
private static final int SICSLOWPAN_NHC_UDP_10 = 0xf2;
private static final int SICSLOWPAN_NHC_UDP_11 = 0xf3;
public final static int PROTO_UDP = 17;
public final static int PROTO_TCP = 6;
public final static int PROTO_ICMP = 58;
public final static byte[] UNSPECIFIED_ADDRESS
= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
public final static byte[] UNSPECIFIED_ADDRESS =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
private static byte[][] addrContexts = new byte[][] {
{(byte)0xaa, (byte)0xaa, 0, 0, 0, 0, 0, 0}
private static byte[][] addrContexts = new byte[][]{
{(byte) 0xaa, (byte) 0xaa, 0, 0, 0, 0, 0, 0}
};
private static final int IPHC_DISPATCH = 0x60;
/* packet must be on network level && have a IPHC dispatch */
@Override
public boolean matchPacket(Packet packet) {
return packet.level == NETWORK_LEVEL && (packet.get(0) & 0xe0) == IPHC_DISPATCH;
}
public int analyzePacket(Packet packet, StringBuffer brief,
StringBuffer verbose) {
@Override
public int analyzePacket(Packet packet, StringBuilder brief,
StringBuilder verbose) {
/* if packet has less than 3 bytes it is not interesting ... */
if (packet.size() < 3) return ANALYSIS_FAILED;
@ -75,10 +82,24 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
int tf = (packet.get(0) >> 3) & 0x03;
boolean nhc = (packet.get(0) & SICSLOWPAN_IPHC_NH_C) > 0;
int hlim = (packet.get(0) & 0x03);
switch (hlim) {
case 0x00:
hlim = 0;
break;
case 0x01:
hlim = 1;
break;
case 0x02:
hlim = 64;
break;
case 0x03:
hlim = 255;
break;
}
int cid = (packet.get(1) >> 7) & 0x01;
int sac = (packet.get(1) >> 6) & 0x01;
int sam = (packet.get(1) >> 4) & 0x03;
int m = (packet.get(1) >> 3) & 0x01;
boolean m = ((packet.get(1) >> 3) & 0x01) != 0;
int dac = (packet.get(1) >> 2) & 0x01;
int dam = packet.get(1) & 0x03;
int sci = 0;
@ -89,14 +110,19 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
brief.append("IPHC");
/* need to decompress while analyzing - add that later... */
verbose.append("<b>IPHC HC-06</b><br>");
verbose.append("tf = " + tf + " nhc = " + nhc + " hlim = " + hlim
+ " cid = " + cid + " sac = " + sac + " sam = " + sam
+ " MCast = " + m + " dac = " + dac + " dam = " + dam);
verbose.append("TF = ").append(tf)
.append(", NH = ").append(nhc ? "compressed" : "inline")
.append(", HLIM = ").append(hlim == 0 ? "inline" : hlim)
.append(", CID = ").append(cid)
.append(", SAC = ").append(sac == 1 ? "stateless" : "stateful")
.append(", SAM = ").append(sam)
.append(", MCast = ").append(m)
.append(", DAC = ").append(dac == 1 ? "stateless" : "stateful")
.append(", DAM = ").append(dam);
if (cid == 1) {
verbose.append("<br>Contexts: sci=" + (packet.get(2) >> 4) + " dci="
+ (packet.get(2) & 0x0f));
verbose.append("<br>Contexts: sci=").append(packet.get(2) >> 4).
append(" dci=").append(packet.get(2) & 0x0f);
sci = packet.get(2) >> 4;
dci = packet.get(2) & 0x0f;
}
@ -115,12 +141,11 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
int srcPort = 0;
int destPort = 0;
try {
/* Traffic class and flow label */
if((packet.get(0) & SICSLOWPAN_IPHC_FL_C) == 0) {
if ((packet.get(0) & SICSLOWPAN_IPHC_FL_C) == 0) {
/* Flow label are carried inline */
if((packet.get(0) & SICSLOWPAN_IPHC_TC_C) == 0) {
if ((packet.get(0) & SICSLOWPAN_IPHC_TC_C) == 0) {
/* Traffic class is carried inline */
flowLabel = packet.getInt(hc06_ptr + 1, 3);
int tmp = packet.get(hc06_ptr);
@ -138,28 +163,28 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
} else {
/* Version is always 6! */
/* Version and flow label are compressed */
if((packet.get(0) & SICSLOWPAN_IPHC_TC_C) == 0) {
if ((packet.get(0) & SICSLOWPAN_IPHC_TC_C) == 0) {
/* Traffic class is inline */
trafficClass =((packet.get(hc06_ptr) >> 6) & 0x03);
trafficClass = ((packet.get(hc06_ptr) >> 6) & 0x03);
trafficClass |= (packet.get(hc06_ptr) << 2);
hc06_ptr += 1;
}
}
/* Next Header */
if((packet.get(0) & SICSLOWPAN_IPHC_NH_C) == 0) {
if ((packet.get(0) & SICSLOWPAN_IPHC_NH_C) == 0) {
/* Next header is carried inline */
proto = packet.get(hc06_ptr);
hc06_ptr += 1;
}
/* Hop limit */
switch(packet.get(0) & 0x03) {
switch (packet.get(0) & 0x03) {
case SICSLOWPAN_IPHC_TTL_1:
ttl = 1;
break;
case SICSLOWPAN_IPHC_TTL_64:
ttl = 2;
ttl = 64;
break;
case SICSLOWPAN_IPHC_TTL_255:
ttl = 255;
@ -171,20 +196,21 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
}
/* context based compression */
if((packet.get(1) & SICSLOWPAN_IPHC_SAC) > 0) {
if ((packet.get(1) & SICSLOWPAN_IPHC_SAC) > 0) {
/* Source address */
byte[] context = null;
if((packet.get(1) & SICSLOWPAN_IPHC_SAM_11) != SICSLOWPAN_IPHC_SAM_00) {
if ((packet.get(1) & SICSLOWPAN_IPHC_SAM_11) != SICSLOWPAN_IPHC_SAM_00) {
context = addrContexts[sci];
}
switch(packet.get(1) & SICSLOWPAN_IPHC_SAM_11) {
switch (packet.get(1) & SICSLOWPAN_IPHC_SAM_11) {
case SICSLOWPAN_IPHC_SAM_00:
/* copy the unspecificed address */
srcAddress = UNSPECIFIED_ADDRESS;
break;
case SICSLOWPAN_IPHC_SAM_01: /* 64 bits */
/* copy prefix from context */
System.arraycopy(context, 0, srcAddress, 0, 8);
/* copy IID from packet */
packet.copy(hc06_ptr, srcAddress, 8, 8);
@ -192,6 +218,7 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
break;
case SICSLOWPAN_IPHC_SAM_10: /* 16 bits */
/* unicast address */
System.arraycopy(context, 0, srcAddress, 0, 8);
/* copy 6 NULL bytes then 2 last bytes of IID */
packet.copy(hc06_ptr, srcAddress, 14, 2);
@ -199,6 +226,7 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
break;
case SICSLOWPAN_IPHC_SAM_11: /* 0-bits */
/* copy prefix from context */
System.arraycopy(context, 0, srcAddress, 0, 8);
/* infer IID from L2 address */
System.arraycopy(packet.llsender, 0, srcAddress,
@ -208,13 +236,15 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
/* end context based compression */
} else {
/* no compression and link local */
switch(packet.get(1) & SICSLOWPAN_IPHC_SAM_11) {
switch (packet.get(1) & SICSLOWPAN_IPHC_SAM_11) {
case SICSLOWPAN_IPHC_SAM_00: /* 128 bits */
/* copy whole address from packet */
packet.copy(hc06_ptr, srcAddress, 0, 16);
hc06_ptr += 16;
break;
case SICSLOWPAN_IPHC_SAM_01: /* 64 bits */
srcAddress[0] = (byte) 0xfe;
srcAddress[1] = (byte) 0x80;
/* copy IID from packet */
@ -222,6 +252,7 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
hc06_ptr += 8;
break;
case SICSLOWPAN_IPHC_SAM_10: /* 16 bits */
srcAddress[0] = (byte) 0xfe;
srcAddress[1] = (byte) 0x80;
packet.copy(hc06_ptr, srcAddress, 14, 2);
@ -229,6 +260,7 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
break;
case SICSLOWPAN_IPHC_SAM_11: /* 0 bits */
/* setup link-local address */
srcAddress[0] = (byte) 0xfe;
srcAddress[1] = (byte) 0x80;
/* infer IID from L2 address */
@ -241,31 +273,35 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
/* Destination address */
/* multicast compression */
if((packet.get(1) & SICSLOWPAN_IPHC_M) != 0) {
if ((packet.get(1) & SICSLOWPAN_IPHC_M) != 0) {
/* context based multicast compression */
if((packet.get(1) & SICSLOWPAN_IPHC_DAC) != 0) {
if ((packet.get(1) & SICSLOWPAN_IPHC_DAC) != 0) {
/* TODO: implement this */
} else {
/* non-context based multicast compression */
switch (packet.get(1) & SICSLOWPAN_IPHC_DAM_11) {
case SICSLOWPAN_IPHC_DAM_00: /* 128 bits */
/* copy whole address from packet */
packet.copy(hc06_ptr, destAddress, 0, 16);
hc06_ptr += 16;
break;
case SICSLOWPAN_IPHC_DAM_01: /* 48 bits FFXX::00XX:XXXX:XXXX */
destAddress[0] = (byte) 0xff;
destAddress[1] = packet.get(hc06_ptr);
packet.copy(hc06_ptr + 1, destAddress, 11, 5);
hc06_ptr += 6;
break;
case SICSLOWPAN_IPHC_DAM_10: /* 32 bits FFXX::00XX:XXXX */
destAddress[0] = (byte) 0xff;
destAddress[1] = packet.get(hc06_ptr);
packet.copy(hc06_ptr + 1, destAddress, 13, 3);
hc06_ptr += 4;
break;
case SICSLOWPAN_IPHC_DAM_11: /* 8 bits FF02::00XX */
destAddress[0] = (byte) 0xff;
destAddress[1] = (byte) 0x02;
destAddress[15] = packet.get(hc06_ptr);
@ -276,11 +312,12 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
} else {
/* no multicast */
/* Context based */
if((packet.get(1) & SICSLOWPAN_IPHC_DAC) != 0) {
if ((packet.get(1) & SICSLOWPAN_IPHC_DAC) != 0) {
byte[] context = addrContexts[dci];
switch (packet.get(1) & SICSLOWPAN_IPHC_DAM_11) {
case SICSLOWPAN_IPHC_DAM_01: /* 64 bits */
System.arraycopy(context, 0, destAddress, 0, 8);
/* copy IID from packet */
packet.copy(hc06_ptr, destAddress, 8, 8);
@ -288,6 +325,7 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
break;
case SICSLOWPAN_IPHC_DAM_10: /* 16 bits */
/* unicast address */
System.arraycopy(context, 0, destAddress, 0, 8);
/* copy IID from packet */
packet.copy(hc06_ptr, destAddress, 14, 2);
@ -295,6 +333,7 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
break;
case SICSLOWPAN_IPHC_DAM_11: /* 0 bits */
/* unicast address */
System.arraycopy(context, 0, destAddress, 0, 8);
/* infer IID from L2 address */
System.arraycopy(packet.llreceiver, 0, destAddress,
@ -305,22 +344,26 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
/* not context based => link local M = 0, DAC = 0 - same as SAC */
switch (packet.get(1) & SICSLOWPAN_IPHC_DAM_11) {
case SICSLOWPAN_IPHC_DAM_00: /* 128 bits */
packet.copy(hc06_ptr, destAddress, 0, 16);
hc06_ptr += 16;
break;
case SICSLOWPAN_IPHC_DAM_01: /* 64 bits */
destAddress[0] = (byte) 0xfe;
destAddress[1] = (byte) 0x80;
packet.copy(hc06_ptr, destAddress, 8, 8);
hc06_ptr += 8;
break;
case SICSLOWPAN_IPHC_DAM_10: /* 16 bits */
destAddress[0] = (byte) 0xfe;
destAddress[1] = (byte) 0x80;
packet.copy(hc06_ptr, destAddress, 14, 2);
hc06_ptr += 2;
break;
case SICSLOWPAN_IPHC_DAM_11: /* 0 bits */
destAddress[0] = (byte) 0xfe;
destAddress[1] = (byte) 0x80;
System.arraycopy(packet.llreceiver, 0, destAddress,
@ -331,38 +374,56 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
}
/* Next header processing - continued */
if(nhc) {
if (nhc) {
/* TODO: check if this is correct in hc-06 */
/* The next header is compressed, NHC is following */
if((packet.get(hc06_ptr) & SICSLOWPAN_NDC_UDP_MASK) == SICSLOWPAN_NHC_UDP_ID) {
if ((packet.get(hc06_ptr) & SICSLOWPAN_NDC_UDP_MASK) == SICSLOWPAN_NHC_UDP_ID) {
proto = PROTO_UDP;
switch(packet.get(hc06_ptr)) {
case (byte) SICSLOWPAN_NHC_UDP_C:
/* 1 byte for NHC, 1 byte for ports, 2 bytes chksum */
srcPort = SICSLOWPAN_UDP_PORT_MIN + (packet.get(hc06_ptr + 1) >> 4);
destPort = SICSLOWPAN_UDP_PORT_MIN + (packet.get(hc06_ptr + 1) & 0x0F);
// memcpy(&SICSLOWPAN_UDP_BUF->udpchksum, hc06_ptr + 2, 2);
// PRINTF("IPHC: Uncompressed UDP ports (4): %x, %x\n",
// SICSLOWPAN_UDP_BUF->srcport, SICSLOWPAN_UDP_BUF->destport);
hc06_ptr += 4;
break;
case (byte) SICSLOWPAN_NHC_UDP_I:
switch (packet.get(hc06_ptr) & (byte) SICSLOWPAN_NHC_UDP_11) {
case (byte) SICSLOWPAN_NHC_UDP_00:
/* 1 byte for NHC, 4 byte for ports, 2 bytes chksum */
srcPort = packet.getInt(hc06_ptr + 1, 2);
destPort = packet.getInt(hc06_ptr + 3, 2);
// memcpy(&SICSLOWPAN_UDP_BUF->udpchksum, hc06_ptr + 5, 2);
// PRINTF("IPHC: Uncompressed UDP ports (7): %x, %x\n",
// SICSLOWPAN_UDP_BUF->srcport, SICSLOWPAN_UDP_BUF->destport);
srcPort = packet.getInt(hc06_ptr + 1, 2) & 0xFFFF;
destPort = packet.getInt(hc06_ptr + 3, 2) & 0xFFFF;
hc06_ptr += 7;
break;
default:
// PRINTF("sicslowpan uncompress_hdr: error unsupported UDP compression\n");
return ANALYSIS_FAILED;
}
case (byte) SICSLOWPAN_NHC_UDP_01:
/* 1 byte for NHC, 3 byte for ports, 2 bytes chksum */
srcPort = packet.getInt(hc06_ptr + 1, 2);
destPort = SICSLOWPAN_UDP_8_BIT_PORT_MIN + (packet.get(hc06_ptr + 3) & 0xFF);
hc06_ptr += 6;
break;
case (byte) SICSLOWPAN_NHC_UDP_10:
/* 1 byte for NHC, 3 byte for ports, 2 bytes chksum */
srcPort = SICSLOWPAN_UDP_8_BIT_PORT_MIN + (packet.get(hc06_ptr + 1) & 0xFF);
destPort = packet.getInt(hc06_ptr + 2, 2);
hc06_ptr += 6;
break;
case (byte) SICSLOWPAN_NHC_UDP_11:
/* 1 byte for NHC, 1 byte for ports, 2 bytes chksum */
srcPort = SICSLOWPAN_UDP_4_BIT_PORT_MIN + (packet.get(hc06_ptr + 1) >> 4);
destPort = SICSLOWPAN_UDP_4_BIT_PORT_MIN + (packet.get(hc06_ptr + 1) & 0x0F);
hc06_ptr += 4;
break;
}
}
} else {
// Skip extension header
// XXX TODO: Handle others, too?
if (proto == EXT_HDR_HOP_BY_HOP) {
proto = packet.get(hc06_ptr) & 0xFF;
// header length is length specified in field, rounded up to 64 bit
int hdr_len = ((packet.get(hc06_ptr + 1) / 8) + 1) * 8;
hc06_ptr += hdr_len;
// UDP hadling
if (proto == PROTO_UDP) {
srcPort = packet.getInt(hc06_ptr, 2) & 0xFFFF;
destPort = packet.getInt(hc06_ptr + 2, 2) & 0xFFFF;
hc06_ptr += 4;
}
}
}
// /* IP length field. */
// if(ip_len == 0) {
@ -374,14 +435,12 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
// SICSLOWPAN_IP_BUF->len[0] = (ip_len - UIP_IPH_LEN) >> 8;
// SICSLOWPAN_IP_BUF->len[1] = (ip_len - UIP_IPH_LEN) & 0x00FF;
// }
// /* length field in UDP header */
// if(SICSLOWPAN_IP_BUF->proto == UIP_PROTO_UDP) {
// memcpy(&SICSLOWPAN_UDP_BUF->udplen, ipBuf + len[0], 2);
// }
/*--------------------------------------------- */
} catch (Exception e) {
// some kind of unexpected error...
error = " error during IPHC parsing: " + e.getMessage();
@ -391,20 +450,44 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
String protoStr = "" + proto;
if (proto == PROTO_ICMP) {
protoStr = "ICMPv6";
} else if (proto == PROTO_UDP) protoStr = "UDP";
else if (proto == PROTO_TCP) protoStr = "TCP";
} else if (proto == PROTO_UDP) {
protoStr = "UDP";
} else if (proto == PROTO_TCP) {
protoStr = "TCP";
} else {
protoStr = String.valueOf(proto);
}
verbose.append("<br><b>IPv6 ").append(protoStr).append("</b> TC = " + trafficClass +
" FL: " + flowLabel + "<br>");
// IPv6 Information
brief.append("|IPv6");
verbose.append("<br/><b>IPv6</b>")
.append(" TC = ").append(trafficClass)
.append(", FL = ").append(flowLabel)
.append("<br>");
verbose.append("From ");
printAddress(verbose, srcAddress);
verbose.append(" to ");
printAddress(verbose, destAddress);
if (error != null) verbose.append(" " + error);
if (error != null) {
verbose.append(" ").append(error);
}
// Application Layer Information
if (proto != PROTO_ICMP) {
brief.append('|').append(protoStr);
verbose.append("<br/><b>").append(protoStr).append("</b>");
}
if (proto == PROTO_UDP) {
brief.append(' ').append(srcPort).append(' ').append(destPort);
verbose.append("<br/>Src Port: ").append(srcPort);
verbose.append(", Dst Port: ").append(destPort);
}
packet.lastDispatch = (byte) (proto & 0xff);
if (proto == PROTO_UDP || proto == PROTO_ICMP ||
proto == PROTO_TCP) {
if (proto == PROTO_UDP || proto == PROTO_ICMP
|| proto == PROTO_TCP) {
packet.level = APPLICATION_LEVEL;
return ANALYSIS_OK_CONTINUE;
} else {
@ -413,15 +496,13 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer {
}
}
public static void printAddress(StringBuffer out, byte[] address) {
for (int i = 0; i < 16; i+=2) {
out.append(StringUtils.toHex((byte) (address[i] & 0xff)) +
StringUtils.toHex((byte) (address[i + 1] & 0xff)));
public static void printAddress(StringBuilder out, byte[] address) {
for (int i = 0; i < 16; i += 2) {
out.append(StringUtils.toHex((byte) (address[i] & 0xff))
+ StringUtils.toHex((byte) (address[i + 1] & 0xff)));
if (i < 14) {
out.append(":");
}
}
}
}

View file

@ -4,32 +4,30 @@ import org.contikios.cooja.util.StringUtils;
public class IPv6PacketAnalyzer extends PacketAnalyzer {
public final static int PROTO_UDP = 17;
public final static int PROTO_TCP = 6;
public final static int PROTO_ICMP = 58;
public final static byte[] UNSPECIFIED_ADDRESS =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
public final static byte[] UNSPECIFIED_ADDRESS
= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
private static final int IPV6_DISPATCH = 0x41;
@Override
public boolean matchPacket(Packet packet) {
return packet.level == NETWORK_LEVEL && packet.get(0) == IPV6_DISPATCH;
}
public int analyzePacket(Packet packet, StringBuffer brief,
StringBuffer verbose) {
@Override
public int analyzePacket(Packet packet, StringBuilder brief,
StringBuilder verbose) {
/* if packet has less than 40 bytes it is not interesting ... */
if (packet.size() < 40) return ANALYSIS_FAILED;
brief.append("IPv6");
/* need to decompress while analyzing - add that later... */
verbose.append("<b>IPv6</b><br>");
int pos = 1;
@ -49,14 +47,18 @@ public class IPv6PacketAnalyzer extends PacketAnalyzer {
String protoStr = "" + proto;
if (proto == PROTO_ICMP) {
protoStr = "ICMPv6";
} else if (proto == PROTO_UDP) protoStr = "UDP";
else if (proto == PROTO_TCP) protoStr = "TCP";
} else if (proto == PROTO_UDP) {
protoStr = "UDP";
} else if (proto == PROTO_TCP) {
protoStr = "TCP";
}
/* consume dispatch + IP header */
packet.pos += 41;
verbose.append("<br><b>IPv6 ").append(protoStr).append("</b> TC = " + trafficClass +
" FL: " + flowLabel + "<br>");
verbose.append("<br><b>IPv6 ").append(protoStr)
.append("</b> TC = ").append(trafficClass)
.append(" FL: ").append(flowLabel).append("<br>");
verbose.append("From ");
printAddress(verbose, srcAddress);
verbose.append(" to ");
@ -67,15 +69,14 @@ public class IPv6PacketAnalyzer extends PacketAnalyzer {
return ANALYSIS_OK_CONTINUE;
}
public static void printAddress(StringBuffer out, byte[] address) {
for (int i = 0; i < 16; i+=2) {
out.append(StringUtils.toHex((byte) (address[i] & 0xff)) +
StringUtils.toHex((byte) (address[i + 1] & 0xff)));
public static void printAddress(StringBuilder out, byte[] address) {
for (int i = 0; i < 16; i += 2) {
out.append(StringUtils.toHex((byte) (address[i] & 0xff))
+ StringUtils.toHex((byte) (address[i + 1] & 0xff)));
if (i < 14) {
out.append(":");
}
}
}
}

View file

@ -12,6 +12,7 @@ public abstract class PacketAnalyzer {
public static final int APPLICATION_LEVEL = 3;
public static class Packet {
byte[] data;
int pos;
int level;
@ -30,7 +31,6 @@ public abstract class PacketAnalyzer {
this.size = data.length;
}
public void consumeBytesStart(int bytes) {
pos += bytes;
}
@ -39,7 +39,6 @@ public abstract class PacketAnalyzer {
size -= bytes;
}
public boolean hasMoreData() {
return size > pos;
}
@ -56,12 +55,11 @@ public abstract class PacketAnalyzer {
public int getInt(int index, int size) {
int value = 0;
for (int i = 0; i < size; i++) {
value = (value << 8) + get(index + i);
value = (value << 8) + (get(index + i) & 0xFF);
}
return value;
}
public byte[] getPayload() {
byte[] pload = new byte[size - pos];
System.arraycopy(data, pos, pload, 0, pload.length);
@ -85,5 +83,5 @@ public abstract class PacketAnalyzer {
public abstract boolean matchPacket(Packet packet);
public abstract int analyzePacket(Packet packet, StringBuffer brief, StringBuffer verbose);
public abstract int analyzePacket(Packet packet, StringBuilder brief, StringBuilder verbose);
}

View file

@ -15,10 +15,10 @@ public class PcapExporter {
}
public void openPcap(File pcapFile) throws IOException {
if ( out != null ) {
if (out != null) {
closePcap();
}
if ( pcapFile == null ) {
if (pcapFile == null) {
/* pcap file not specified, use default file name */
pcapFile = new File("radiolog-" + System.currentTimeMillis() + ".pcap");
}
@ -31,9 +31,11 @@ public class PcapExporter {
out.writeInt(0);
out.writeInt(4096);
out.writeInt(195); /* 195 for LINKTYPE_IEEE802_15_4 */
out.flush();
System.out.println("Opened pcap file " + pcapFile);
}
public void closePcap() throws IOException {
out.close();
out = null;
@ -58,6 +60,4 @@ public class PcapExporter {
}
}
}