diff --git a/tools/cooja/java/org/contikios/cooja/interfaces/IPAddress.java b/tools/cooja/java/org/contikios/cooja/interfaces/IPAddress.java index a0263d077..2c47d3867 100644 --- a/tools/cooja/java/org/contikios/cooja/interfaces/IPAddress.java +++ b/tools/cooja/java/org/contikios/cooja/interfaces/IPAddress.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2014, TU Braunschweig. * Copyright (c) 2006, Swedish Institute of Computer Science. * All rights reserved. * @@ -30,184 +31,275 @@ package org.contikios.cooja.interfaces; import java.util.Collection; +import java.util.LinkedList; +import java.util.List; import java.util.Observable; import java.util.Observer; - import javax.swing.JLabel; import javax.swing.JPanel; - import org.apache.log4j.Logger; -import org.jdom.Element; - import org.contikios.cooja.ClassDescription; import org.contikios.cooja.Mote; import org.contikios.cooja.MoteInterface; import org.contikios.cooja.mote.memory.MemoryInterface; import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor; +import org.contikios.cooja.mote.memory.MemoryLayout; import org.contikios.cooja.mote.memory.VarMemory; +import org.contikios.cooja.util.IPUtils; +import org.jdom.Element; /** * Read-only interface to IPv4 or IPv6 address. * * @author Fredrik Osterlind + * @author Enrico Joerns */ -@ClassDescription("IP Address") +@ClassDescription("IP Addresses") public class IPAddress extends MoteInterface { - private static Logger logger = Logger.getLogger(IPAddress.class); - private final VarMemory moteMem; + private static final Logger logger = Logger.getLogger(IPAddress.class); private static final int IPv6_MAX_ADDRESSES = 4; - private boolean ipv6IsGlobal = false; - private int ipv6AddressIndex = -1; - private static final int MONITORED_SIZE = 150; - private SegmentMonitor memMonitor; + + private enum IPv { + NONE, + IPv4, + IPv6 + } + + private final IPv ipVersion; + + private final VarMemory moteMem; + private final MemoryLayout memLayout; + private IPContainer localIPAddr = null; + + private final SegmentMonitor memMonitor; + + private List ipList = new LinkedList<>(); + + private int ipv6_addr_size = 0; + private int ipv6_addr_list_offset = 0; public IPAddress(final Mote mote) { moteMem = new VarMemory(mote.getMemory()); + memLayout = mote.getMemory().getLayout(); + /* If the ip memory sections changed, we recalculate addresses + * and notify our observers.*/ memMonitor = new MemoryInterface.SegmentMonitor() { + int accessCount = 0; + long lastAccess = 0; @Override public void memoryChanged(MemoryInterface memory, SegmentMonitor.EventType type, long address) { if (type != SegmentMonitor.EventType.WRITE) { return; } - setChanged(); - notifyObservers(); + + /* XXX Quick & Dirty IPv4 update handle */ + if (ipVersion == IPv.IPv4) { + updateIPAddresses(); + setChanged(); + notifyObservers(); + return; + } + + /* Wait until size and offsest values are set initially, + * then add memory monitor for each ip field */ + if ((ipv6_addr_list_offset == 0) || (ipv6_addr_size == 0)) { + ipv6_addr_list_offset = moteMem.getByteValueOf("uip_ds6_netif_addr_list_offset"); + ipv6_addr_size = moteMem.getByteValueOf("uip_ds6_addr_size"); + /* If the variables just updated, add the final ip listeners */ + if ((ipv6_addr_list_offset != 0) && (ipv6_addr_size != 0)) { + /* Add monitor for each IP region */ + for (int i = 0; i < IPv6_MAX_ADDRESSES; i++) { + long addr_of_ip = moteMem.getVariableAddress("uip_ds6_if") // start address of interface + + ipv6_addr_list_offset // offset to ip address region + + i * ipv6_addr_size // offset to ith ip address + + 1 + memory.getLayout().getPaddingBytesFor( + MemoryLayout.DataType.INT8, + MemoryLayout.DataType.INT16); // skip 'isused' + moteMem.addMemoryMonitor( + EventType.WRITE, + addr_of_ip, + 16, /* Size of ip address in byte */ + memMonitor); + } + /* Initial scan for IP address */ + updateIPAddresses(); + if (ipList.size() > 0) { + setChanged(); + notifyObservers(); + } + /** @TODO: Remove other listeners? */ + } + } else { + + /** Note: works when 'isused' bit is set first + * and address region is written sequentially */ + + /* check for sequential reading of 16 byte block */ + if (address == lastAccess + 1) { + accessCount++; + lastAccess = address; + if (accessCount == 16) { + updateIPAddresses(); + setChanged(); + notifyObservers(); + lastAccess = 0; + } + } + else { + /* Check if ip write was interrupted unexpectedly last time */ + if (lastAccess != 0) { + updateIPAddresses(); + setChanged(); + notifyObservers(); + } + accessCount = 1; + lastAccess = address; + } + } } }; - if (isVersion4()) { - moteMem.addVarMonitor(SegmentMonitor.EventType.WRITE, "uip_hostaddr", memMonitor); - } else if (isVersion6()) { - moteMem.addVarMonitor(SegmentMonitor.EventType.WRITE, "uip_ds6_netif_addr_list_offset", memMonitor); - moteMem.addVarMonitor(SegmentMonitor.EventType.WRITE, "uip_ds6_addr_size", memMonitor); - moteMem.addVarMonitor(SegmentMonitor.EventType.WRITE, "uip_ds6_if", memMonitor); + + /* Determine IP version an add MemoryMonitors */ + if (moteMem.variableExists("uip_hostaddr")) { + logger.debug("IPv4 detected"); + ipVersion = IPv.IPv4; + moteMem.addVarMonitor( + SegmentMonitor.EventType.WRITE, + "uip_hostaddr", + memMonitor); + } else if (moteMem.variableExists("uip_ds6_netif_addr_list_offset") + && moteMem.variableExists("uip_ds6_addr_size") + && moteMem.variableExists("uip_ds6_if")) { + logger.debug("IPv6 detected"); + ipVersion = IPv.IPv6; + moteMem.addVarMonitor( + SegmentMonitor.EventType.WRITE, + "uip_ds6_netif_addr_list_offset", + memMonitor); + moteMem.addVarMonitor( + SegmentMonitor.EventType.WRITE, + "uip_ds6_addr_size", + memMonitor); + } else { + ipVersion = IPv.NONE; } + + // initially look for IPs we already have + updateIPAddresses(); + } + + /** + * Returns true if any IP stack (Ipv4/6) is supported by mote + * @return true if either IPv4 or IPv6 was detected + */ + public boolean hasIP() { + return !(ipVersion == IPv.NONE); + } + + /** + * Get local IP of mote. + * @return local IP or null if not existing + */ + public IPContainer getLocalIP() { + return localIPAddr; } /** * Returns IP address string. * Supports both IPv4 and IPv6 addresses. * + * @param idx * @return IP address string */ - public String getIPString() { - if (isVersion4()) { - String ipString = ""; - byte[] ip = moteMem.getByteArray("uip_hostaddr", 4); - for (int i=0; i < 3; i++) { - ipString += (0xFF & ip[i]) + "."; + public IPContainer getIP(int idx) { + try { + return ipList.get(idx); + } catch (IndexOutOfBoundsException ex) { + logger.warn("Invalid IP index " + idx); + return null; + } + } + + /** + * Rereads IP addresses from memory and updates localIP entry. + */ + private void updateIPAddresses() { + ipList.clear(); + if (ipVersion == IPv.IPv4) { + addIPv4Addresses(); + localIPAddr = ipList.get(0); + } + else if (ipVersion == IPv.IPv6) { + addIPv6Addresses(); + /* look for local ip addr */ + for (IPContainer c : ipList) { + if (!c.isGlobal) { + localIPAddr = c; + } } - ipString += (0xFF & ip[3]); - return ipString; - } else if (isVersion6()) { - String ipString = getUncompressedIPv6Address(); - return compressIPv6Address(ipString); } - return null; - } - - public static String compressIPv6Address(String ipString) { - if (ipString.contains(":0000:0000:0000:0000:")) { - ipString = ipString.replace(":0000:0000:0000:0000:", "::"); - } else if (ipString.contains(":0000:0000:0000:")) { - ipString = ipString.replace(":0000:0000:0000:", "::"); - } else if (ipString.contains(":0000:0000:")) { - ipString = ipString.replace(":0000:0000:", "::"); - } else if (ipString.contains(":0000:")) { - ipString = ipString.replace(":0000:", "::"); - } - while (ipString.contains(":0")) { - ipString = ipString.replaceAll(":0", ":"); - } - return ipString; - } - - public byte[] getIPv6Address() { - byte[] ip = null; - - /* IpV6: Struct sizes and offsets */ - int ipv6NetworkInterfaceAddressOffset = moteMem.getByteValueOf("uip_ds6_netif_addr_list_offset"); - int ipv6AddressStructSize = moteMem.getByteValueOf("uip_ds6_addr_size"); - if (ipv6NetworkInterfaceAddressOffset == 0 || ipv6AddressStructSize == 0) { - return null; - } - - /* TODO No need to copy the entire array! */ - byte[] structData = moteMem.getByteArray("uip_ds6_if", - ipv6NetworkInterfaceAddressOffset+IPv6_MAX_ADDRESSES*ipv6AddressStructSize); - - ipv6AddressIndex = -1; - for (int addressIndex=0; addressIndex < IPv6_MAX_ADDRESSES; addressIndex++) { - int offset = ipv6NetworkInterfaceAddressOffset+addressIndex*ipv6AddressStructSize; - byte isUsed = structData[offset]; - if (isUsed == 0) { - continue; - } - byte[] addressData = new byte[16]; - System.arraycopy( - structData, offset+2/* ipaddr offset */, - addressData, 0, 16); - - if (addressData[0] == (byte)0xFE && addressData[1] == (byte)0x80) { - ipv6IsGlobal = false; - } else { - ipv6IsGlobal = true; - } - - ip = addressData; - ipv6AddressIndex = addressIndex; - if (ipv6IsGlobal) { - break; - } - } - if (ip == null) { - ip = new byte[16]; - ipv6AddressIndex = -1; - } - return ip; - } - - public static String getUncompressedIPv6AddressString(byte[] ip) { - StringBuilder sb = new StringBuilder(); - for (int i=0; i < 14; i+=2) { - sb.append(String.format("%02x%02x:", 0xFF&ip[i+0], 0xFF&ip[i+1])); - } - sb.append(String.format("%02x%02x", 0xFF&ip[14], 0xFF&ip[15])); - return sb.toString(); - } - - public String getUncompressedIPv6Address() { - byte[] ip = getIPv6Address(); - if (ip == null) { - return ""; - } - return getUncompressedIPv6AddressString(ip); } /** - * @return True if mote has an IPv4 address + * Rereads IPv4 addresses from memory. */ - public boolean isVersion4() { - return moteMem.variableExists("uip_hostaddr"); + private void addIPv4Addresses() { + ipList.add(new IPContainer(0, moteMem.getByteArray("uip_hostaddr", 4), true)); } /** - * @return True if mote has an IPv6 address + * Rereads IPv6 addresses from memory. */ - public boolean isVersion6() { - return - moteMem.variableExists("uip_ds6_netif_addr_list_offset") && - moteMem.variableExists("uip_ds6_addr_size") && - moteMem.variableExists("uip_ds6_if"); + private void addIPv6Addresses() { + + /* IpV6: Struct sizes and offsets */ + int ipv6NetworkInterfaceAddressOffset = moteMem.getByteValueOf("uip_ds6_netif_addr_list_offset"); + int ipv6AddressStructSize = moteMem.getByteValueOf("uip_ds6_addr_size"); + /* check if addresses were not set yet */ + if (ipv6NetworkInterfaceAddressOffset == 0 || ipv6AddressStructSize == 0) { + return; + } + + byte[] structData = moteMem.getByteArray( + moteMem.getVariableAddress("uip_ds6_if") + ipv6NetworkInterfaceAddressOffset, + IPv6_MAX_ADDRESSES * ipv6AddressStructSize); + + for (int addressIndex = 0; addressIndex < IPv6_MAX_ADDRESSES; addressIndex++) { + int offset = addressIndex * ipv6AddressStructSize; + byte isUsed = structData[offset]; + if (isUsed == 0) { + continue; + } + byte[] addressData = new byte[16]; + System.arraycopy( + structData, offset + 1 + memLayout.getPaddingBytesFor( + MemoryLayout.DataType.INT8, + MemoryLayout.DataType.INT16),/* ipaddr offset */ + addressData, 0, 16); + + if (((addressData[0] & (byte) 0xFF) == (byte) 0xFE) && ((addressData[1] & (byte) 0xFF) == (byte) 0x80)) { + ipList.add(new IPContainer(addressIndex, addressData, false)); + } + else { + ipList.add(new IPContainer(addressIndex, addressData, true)); + } + + } } + // -- MoteInterface overrides + + @Override public void removed() { super.removed(); if (memMonitor != null) { - if (isVersion4()) { - moteMem.removeVarMonitor("rimeaddr_node_addr", memMonitor); - } else if (isVersion6()) { + if (ipVersion == IPv.IPv4) { + moteMem.removeVarMonitor("uip_hostaddr",memMonitor); + } + else if (ipVersion == IPv.IPv6) { moteMem.removeVarMonitor("uip_ds6_netif_addr_list_offset", memMonitor); moteMem.removeVarMonitor("uip_ds6_addr_size", memMonitor); moteMem.removeVarMonitor("uip_ds6_if", memMonitor); @@ -215,21 +307,37 @@ public class IPAddress extends MoteInterface { } } + @Override public JPanel getInterfaceVisualizer() { JPanel panel = new JPanel(); final JLabel ipLabel = new JLabel(); Observer observer; this.addObserver(observer = new Observer() { + @Override public void update(Observable obs, Object obj) { - if (isVersion4()) { - ipLabel.setText("IPv4 address: " + getIPString()); - } else if (isVersion6()) { - ipLabel.setText((ipv6IsGlobal?"Global":"Local") + - " IPv6 address(#" + ipv6AddressIndex + "): " + getIPString()); - } else { - ipLabel.setText("Unknown IP"); + StringBuilder ipStr = new StringBuilder(); + ipStr.append(""); + for (IPContainer ipc: ipList) { + if (ipVersion == IPv.IPv4) { + ipStr.append("IPv4 address: ") + .append(ipc.toString()) + .append("
"); + } + else if (ipVersion == IPv.IPv6) { + ipStr.append(ipc.isGlobal() ? "Global" : "Local") + .append(" IPv6 address(#") + .append(ipc.getAddID()) + .append("): ") + .append(ipc.toString()) + .append("
"); + } + else { + ipStr.append("Unknown IP
"); + } } + ipStr.append(""); + ipLabel.setText(ipStr.toString()); } }); observer.update(null, null); @@ -240,6 +348,7 @@ public class IPAddress extends MoteInterface { return panel; } + @Override public void releaseInterfaceVisualizer(JPanel panel) { Observer observer = (Observer) panel.getClientProperty("intf_obs"); if (observer == null) { @@ -249,10 +358,68 @@ public class IPAddress extends MoteInterface { this.deleteObserver(observer); } + @Override public Collection getConfigXML() { return null; } + @Override public void setConfigXML(Collection configXML, boolean visAvailable) { } + + /** + * Holds a single IP address. + * + * Note: The compressed IP version is already computed in constructor + */ + public class IPContainer { + + private boolean isGlobal = false; + private final byte[] ip; + private final int addrIdx; + private final String cprString; + + public IPContainer(int addidx, byte[] ip, boolean global) { + this.addrIdx = addidx; + this.ip = ip; + this.isGlobal = global; + if (ipVersion == IPv.IPv4) { + cprString = IPUtils.getIPv4AddressString(ip); + } else if (ipVersion == IPv.IPv6) { + cprString = IPUtils.getCompressedIPv6AddressString(ip); + } else { + cprString = ""; + } + /* logger.info("Added new IP: " + cprString); */ + } + + public int getAddID() { + return addrIdx; + } + + public boolean isGlobal() { + return isGlobal; + } + + public byte[] getIP() { + return ip; + } + + @Override + public String toString() { + return cprString; + } + + public String toUncompressedString() { + if (ipVersion == IPv.IPv4) { + return cprString; + } + else if (ipVersion == IPv.IPv6) { + return IPUtils.getUncompressedIPv6AddressString(ip); + } + else { + return ""; + } + } + } } diff --git a/tools/cooja/java/org/contikios/cooja/mote/memory/Memory.java b/tools/cooja/java/org/contikios/cooja/mote/memory/Memory.java index 4f405a07c..a308b1f2d 100644 --- a/tools/cooja/java/org/contikios/cooja/mote/memory/Memory.java +++ b/tools/cooja/java/org/contikios/cooja/mote/memory/Memory.java @@ -29,6 +29,8 @@ */ package org.contikios.cooja.mote.memory; +import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor; +import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor.EventType; import org.contikios.cooja.mote.memory.MemoryLayout.DataType; /** @@ -151,6 +153,18 @@ public abstract class Memory { return MemoryBuffer.wrap(memIntf.getLayout(), memIntf.getMemorySegment(addr, memIntf.getLayout().addrSize)).getAddr(); } + /** + * Read byte array starting at given address. + * + * @param addr Start address to read from + * @param length Numbe of bytes to read + * @return byte array read from location assigned to variable name + */ + public byte[] getByteArray(long addr, int length) + throws UnknownVariableException { + return memIntf.getMemorySegment(addr, length); + } + // -- Set fixed size types /** * Write 8 bit integer to address. @@ -253,4 +267,38 @@ public abstract class Memory { memIntf.setMemorySegment(addr, MemoryBuffer.wrap(memIntf.getLayout(), new byte[memIntf.getLayout().addrSize]).putAddr(value).getBytes()); } + /** + * Write byte array starting at given address. + * + * @param addr Start address to write to + * @param data data to write + */ + public void setByteArray(long addr, byte[] data) + throws UnknownVariableException { + memIntf.setMemorySegment(addr, data); + } + + /** + * Adds monitor to specified memory region. + * + * @param flag Select memory operation(s) to listen for (read, write, read/write) + * @param addr Start address of monitored region + * @param size Size of monitored region + * @param mm Monitor to add + * @return if monitor could be added, false if not + */ + public boolean addMemoryMonitor(EventType flag, long addr, int size, SegmentMonitor mm) { + return memIntf.addSegmentMonitor(flag, addr, size, mm); + } + + /** + * Removes monitor assigned to the specified region. + * + * @param addr Start address of monitored region + * @param size Size of monitored region + * @param mm Monitor to remove + */ + public void removeMemoryMonitor(long addr, int size, SegmentMonitor mm) { + memIntf.removeSegmentMonitor(addr, size, mm); + } } diff --git a/tools/cooja/java/org/contikios/cooja/mote/memory/VarMemory.java b/tools/cooja/java/org/contikios/cooja/mote/memory/VarMemory.java index 2559fe2f1..65cff9af7 100644 --- a/tools/cooja/java/org/contikios/cooja/mote/memory/VarMemory.java +++ b/tools/cooja/java/org/contikios/cooja/mote/memory/VarMemory.java @@ -243,7 +243,7 @@ public class VarMemory extends Memory { */ public byte[] getByteArray(String varName, int length) throws UnknownVariableException { - return memIntf.getMemorySegment(getVariable(varName).addr, length); + return getByteArray(getVariable(varName).addr, length); } /** @@ -349,23 +349,23 @@ public class VarMemory extends Memory { } /** + * Write byte array starting at location associated with this variable name. * - * @param varName - * @param data + * @param varName Variable name + * @param data data to write */ public void setByteArray(String varName, byte[] data) throws UnknownVariableException { - memIntf.setMemorySegment(getVariable(varName).addr, data); + setByteArray(getVariable(varName).addr, data); } /** - * Adds a MemoryMonitor for the specified address region. + * Adds a monitor for the specified address region. * - * @param flag Select memory operation(s) to listen for (read, write, - * read/write) - * @param varName - * @param mm - * @return + * @param flag Select memory operation(s) to listen for (read, write, read/write) + * @param varName Name of variable to monitor + * @param mm Monitor to add + * @return if monitor could be added, false if not */ public boolean addVarMonitor(EventType flag, final String varName, final SegmentMonitor mm) { return memIntf.addSegmentMonitor( @@ -376,10 +376,10 @@ public class VarMemory extends Memory { } /** - * Removes MemoryMonitor assigned to the specified region. + * Removes monitor assigned to the specified region. * - * @param varName - * @param mm MemoryMonitor to remove + * @param varName Name of monitored variable + * @param mm Monitor to remove */ public void removeVarMonitor(String varName, SegmentMonitor mm) { memIntf.removeSegmentMonitor(getVariable(varName).addr, getVariable(varName).size, mm); diff --git a/tools/cooja/java/org/contikios/cooja/plugins/BufferListener.java b/tools/cooja/java/org/contikios/cooja/plugins/BufferListener.java index aa668b66b..2a67d0243 100644 --- a/tools/cooja/java/org/contikios/cooja/plugins/BufferListener.java +++ b/tools/cooja/java/org/contikios/cooja/plugins/BufferListener.java @@ -104,6 +104,7 @@ import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor; import org.contikios.cooja.mote.memory.VarMemory; import org.contikios.cooja.motes.AbstractEmulatedMote; import org.contikios.cooja.util.ArrayQueue; +import org.contikios.cooja.util.IPUtils; import org.contikios.cooja.util.StringUtils; /** @@ -1696,7 +1697,7 @@ public class BufferListener extends VisPlugin { } else { mem = ba.mem; } - return IPAddress.compressIPv6Address(StringUtils.toHex(mem, 2).replaceAll(" ", ":")); + return IPUtils.getCompressedIPv6AddressString(mem); } } @@ -1708,15 +1709,7 @@ public class BufferListener extends VisPlugin { if (ba.mem.length < 4) { return "[must monitor at least 4 bytes]"; } - StringBuilder sb = new StringBuilder(); - sb.append(0xff&ba.mem[0]); - sb.append("."); - sb.append(0xff&ba.mem[1]); - sb.append("."); - sb.append(0xff&ba.mem[2]); - sb.append("."); - sb.append(0xff&ba.mem[3]); - return sb.toString(); + return IPUtils.getIPv4AddressString(ba.mem); } } diff --git a/tools/cooja/java/org/contikios/cooja/plugins/analyzers/IPHCPacketAnalyzer.java b/tools/cooja/java/org/contikios/cooja/plugins/analyzers/IPHCPacketAnalyzer.java index b6121c6ce..80b1c72cb 100644 --- a/tools/cooja/java/org/contikios/cooja/plugins/analyzers/IPHCPacketAnalyzer.java +++ b/tools/cooja/java/org/contikios/cooja/plugins/analyzers/IPHCPacketAnalyzer.java @@ -1,6 +1,6 @@ package org.contikios.cooja.plugins.analyzers; -import org.contikios.cooja.util.StringUtils; +import org.contikios.cooja.util.IPUtils; public class IPHCPacketAnalyzer extends PacketAnalyzer { @@ -466,9 +466,9 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer { .append(", FL = ").append(flowLabel) .append("
"); verbose.append("From "); - printAddress(verbose, srcAddress); + IPUtils.getUncompressedIPv6AddressString(verbose, srcAddress); verbose.append(" to "); - printAddress(verbose, destAddress); + IPUtils.getUncompressedIPv6AddressString(verbose, destAddress); if (error != null) { verbose.append(" ").append(error); } @@ -496,13 +496,4 @@ public class IPHCPacketAnalyzer extends PacketAnalyzer { } } - 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(":"); - } - } - } } diff --git a/tools/cooja/java/org/contikios/cooja/plugins/analyzers/IPv6PacketAnalyzer.java b/tools/cooja/java/org/contikios/cooja/plugins/analyzers/IPv6PacketAnalyzer.java index 0d33b0bd3..4ecc99e4a 100644 --- a/tools/cooja/java/org/contikios/cooja/plugins/analyzers/IPv6PacketAnalyzer.java +++ b/tools/cooja/java/org/contikios/cooja/plugins/analyzers/IPv6PacketAnalyzer.java @@ -1,6 +1,6 @@ package org.contikios.cooja.plugins.analyzers; -import org.contikios.cooja.util.StringUtils; +import org.contikios.cooja.util.IPUtils; public class IPv6PacketAnalyzer extends PacketAnalyzer { @@ -60,23 +60,13 @@ public class IPv6PacketAnalyzer extends PacketAnalyzer { .append(" TC = ").append(trafficClass) .append(" FL: ").append(flowLabel).append("
"); verbose.append("From "); - printAddress(verbose, srcAddress); + IPUtils.getUncompressedIPv6AddressString(verbose, srcAddress); verbose.append(" to "); - printAddress(verbose, destAddress); + IPUtils.getUncompressedIPv6AddressString(verbose, destAddress); packet.lastDispatch = (byte) (proto & 0xff); packet.level = APPLICATION_LEVEL; return ANALYSIS_OK_CONTINUE; } - 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(":"); - } - } - } - } diff --git a/tools/cooja/java/org/contikios/cooja/plugins/skins/AddressVisualizerSkin.java b/tools/cooja/java/org/contikios/cooja/plugins/skins/AddressVisualizerSkin.java index e8dbefd02..44a77fc6a 100644 --- a/tools/cooja/java/org/contikios/cooja/plugins/skins/AddressVisualizerSkin.java +++ b/tools/cooja/java/org/contikios/cooja/plugins/skins/AddressVisualizerSkin.java @@ -128,8 +128,11 @@ public class AddressVisualizerSkin implements VisualizerSkin { private static String getMoteString(Mote mote) { IPAddress ipAddr = mote.getInterfaces().getIPAddress(); - if (ipAddr != null && ipAddr.getIPString() != null) { - return ipAddr.getIPString(); + if ((ipAddr != null) && (ipAddr.hasIP())) { + if (ipAddr.getLocalIP() == null) { + return ""; + } + return ipAddr.getLocalIP().toString(); } RimeAddress rimeAddr = mote.getInterfaces().getRimeAddress(); diff --git a/tools/cooja/java/org/contikios/cooja/util/IPUtils.java b/tools/cooja/java/org/contikios/cooja/util/IPUtils.java new file mode 100644 index 000000000..18dae27e1 --- /dev/null +++ b/tools/cooja/java/org/contikios/cooja/util/IPUtils.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2014, TU Braunschweig + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +package org.contikios.cooja.util; + +/** + * Holds some IP byte to string conversion functions etc. + * + * @author Enrico Jorns + */ +public class IPUtils { + + /** + * Convert IPv6 Byte-array in compressed IPv6-Address String. + * + * @param ip byte array holding IPv6 address information + * @return String representation + */ + public static String getCompressedIPv6AddressString(byte[] ip) { + StringBuilder build = new StringBuilder(); + IPUtils.getCompressedIPv6AddressString(build, ip); + return build.toString(); + } + + /** + * Convert IPv6 Byte-array in compressed IPv6-Address String. + * + * @param builder Buffer to append to + * @param ip byte array holding IPv6 address information + */ + public static void getCompressedIPv6AddressString(StringBuilder builder, byte[] ip) { + int startMax = 0, startCurr = 0, zeroMax = 0, zeroCurr = 0; + + if (ip.length != 16) { + throw new IllegalArgumentException("Invalid array length: " + ip.length); + } + + for (int i = 0; i < 16; i += 2) { + if ((ip[i] | ip[i + 1]) == 0x00) { + if (zeroCurr == 0) { + startCurr = i; + } + zeroCurr++; + } + else { + if (zeroCurr > zeroMax) { + zeroMax = zeroCurr; + startMax = startCurr; + zeroCurr = 0; + } + } + } + if (zeroCurr > zeroMax) { + zeroMax = zeroCurr; + startMax = startCurr; + } + + short a; + for (int i = 0, f = 0; i < 16; i += 2) { + a = (short) (((ip[i] & 0xFF) << 8) + (ip[i + 1] & 0xFF)); + if ((i >= startMax) && (i < startMax + zeroMax * 2)) { + if (f++ == 0) { + builder.append("::"); + } + } + else { + if (f > 0) { + f = -1; + } + else if (i > 0) { + builder.append(':'); + } + builder.append(String.format("%x", a)); + } + } + } + + /** + * Convert IPv6 Byte-array in uncompressed IPv6-Address String. + * + * @param ip byte array holding IPv6 address information + * @return uncompressed IPv6 representation string + */ + public static String getUncompressedIPv6AddressString(byte[] ip) { + StringBuilder ipBuilder = new StringBuilder(); + IPUtils.getUncompressedIPv6AddressString(ipBuilder, ip); + return ipBuilder.toString(); + } + + /** + * Convert IPv6 Byte-array in uncompressed IPv6-Address String. + * + * @param builder StringBuilder to append address to + * @param ip byte array holding IPv6 address information + */ + public static void getUncompressedIPv6AddressString(StringBuilder builder, byte[] ip) { + for (int i = 0; i < 14; i += 2) { + builder.append(String.format("%02x%02x:", 0xFF & ip[i + 0], 0xFF & ip[i + 1])); + } + builder.append(String.format("%02x%02x", 0xFF & ip[14], 0xFF & ip[15])); + } + + /** + * Convert IPv4 Byte-array to IPv4-Address String. + * + * @param ip byte array holding IPv4 address information + * @return IPv4 representation string + */ + public static String getIPv4AddressString(byte[] ip) { + + if (ip.length != 4) { + throw new IllegalArgumentException("Invalid array length: " + ip.length); + } + + StringBuilder ipBuilder = new StringBuilder(); + for (int i = 0; i < 3; i++) { + ipBuilder.append(0xFF & ip[i]); + ipBuilder.append('.'); + } + ipBuilder.append(0xFF & ip[3]); + return ipBuilder.toString(); + } + +}