diff --git a/staticlibs/device/com/android/net/module/util/HexDump.java b/staticlibs/device/com/android/net/module/util/HexDump.java index d8c0fb5625..6d36487b07 100644 --- a/staticlibs/device/com/android/net/module/util/HexDump.java +++ b/staticlibs/device/com/android/net/module/util/HexDump.java @@ -20,9 +20,6 @@ import android.annotation.Nullable; /** * Hex utility functions. - * - * A copy from frameworks/base/core/java/com/android/internal/util/HexDump.java, to be shared - * by multiple modules. */ public class HexDump { private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java index afc2e646d9..f11a5acea5 100644 --- a/staticlibs/device/com/android/net/module/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -27,6 +27,10 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.math.BigInteger; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -99,21 +103,23 @@ import java.util.concurrent.ConcurrentHashMap; */ public class Struct { public enum Type { - U8, // unsigned byte, size = 1 byte - U16, // unsigned short, size = 2 bytes - U32, // unsigned int, size = 4 bytes - U63, // unsigned long(MSB: 0), size = 8 bytes - U64, // unsigned long, size = 8 bytes - S8, // signed byte, size = 1 byte - S16, // signed short, size = 2 bytes - S32, // signed int, size = 4 bytes - S64, // signed long, size = 8 bytes - UBE16, // unsigned short in network order, size = 2 bytes - UBE32, // unsigned int in network order, size = 4 bytes - UBE63, // unsigned long(MSB: 0) in network order, size = 8 bytes - UBE64, // unsigned long in network order, size = 8 bytes - ByteArray, // byte array with predefined length - EUI48, // IEEE Extended Unique Identifier, a 48-bits long MAC address in network order + U8, // unsigned byte, size = 1 byte + U16, // unsigned short, size = 2 bytes + U32, // unsigned int, size = 4 bytes + U63, // unsigned long(MSB: 0), size = 8 bytes + U64, // unsigned long, size = 8 bytes + S8, // signed byte, size = 1 byte + S16, // signed short, size = 2 bytes + S32, // signed int, size = 4 bytes + S64, // signed long, size = 8 bytes + UBE16, // unsigned short in network order, size = 2 bytes + UBE32, // unsigned int in network order, size = 4 bytes + UBE63, // unsigned long(MSB: 0) in network order, size = 8 bytes + UBE64, // unsigned long in network order, size = 8 bytes + ByteArray, // byte array with predefined length + EUI48, // IEEE Extended Unique Identifier, a 48-bits long MAC address in network order + Ipv4Address, // IPv4 address in network order + Ipv6Address, // IPv6 address in network order } /** @@ -186,6 +192,12 @@ public class Struct { case EUI48: if (fieldType == MacAddress.class) return; break; + case Ipv4Address: + if (fieldType == Inet4Address.class) return; + break; + case Ipv6Address: + if (fieldType == Inet6Address.class) return; + break; default: throw new IllegalArgumentException("Unknown type" + annotation.type()); } @@ -223,6 +235,12 @@ public class Struct { case EUI48: length = 6; break; + case Ipv4Address: + length = 4; + break; + case Ipv6Address: + length = 16; + break; default: throw new IllegalArgumentException("Unknown type" + annotation.type()); } @@ -388,6 +406,17 @@ public class Struct { buf.get(macAddress); value = MacAddress.fromBytes(macAddress); break; + case Ipv4Address: + case Ipv6Address: + final boolean isIpv6 = (fieldInfo.annotation.type() == Type.Ipv6Address); + final byte[] address = new byte[isIpv6 ? 16 : 4]; + buf.get(address); + try { + value = InetAddress.getByAddress(address); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("illegal length of IP address", e); + } + break; default: throw new IllegalArgumentException("Unknown type:" + fieldInfo.annotation.type()); } @@ -461,6 +490,11 @@ public class Struct { final byte[] macAddress = ((MacAddress) value).toByteArray(); output.put(macAddress); break; + case Ipv4Address: + case Ipv6Address: + final byte[] address = ((InetAddress) value).getAddress(); + output.put(address); + break; default: throw new IllegalArgumentException("Unknown type:" + fieldInfo.annotation.type()); } @@ -671,8 +705,11 @@ public class Struct { } if (value == null) { sb.append("null"); - } else if (fieldInfos[i].field.getType() == byte[].class) { + } else if (fieldInfos[i].annotation.type() == Type.ByteArray) { sb.append("0x").append(HexDump.toHexString((byte[]) value)); + } else if (fieldInfos[i].annotation.type() == Type.Ipv4Address + || fieldInfos[i].annotation.type() == Type.Ipv6Address) { + sb.append(((InetAddress) value).getHostAddress()); } else { sb.append(value.toString()); } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java index 7e6c7e2157..5a15585d20 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java @@ -42,7 +42,7 @@ public class HexDumpTest { } @Test - public void testHexStringToBytes() { + public void testHexStringToByteArray() { assertArrayEquals(new byte[]{(byte) 0xab, (byte) 0xcd, (byte) 0xef}, HexDump.hexStringToByteArray("abcdef")); assertArrayEquals(new byte[]{(byte) 0xAB, (byte) 0xCD, (byte) 0xEF}, @@ -50,13 +50,13 @@ public class HexDumpTest { } @Test - public void testIntegerToBytes() { + public void testIntegerToByteArray() { assertArrayEquals(new byte[]{(byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x04}, HexDump.toByteArray((int) 0xff000004)); } @Test - public void testByteToBytes() { + public void testByteToByteArray() { assertArrayEquals(new byte[]{(byte) 0x7f}, HexDump.toByteArray((byte) 0x7f)); } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index 253b9118b9..b172e2142b 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import android.net.InetAddresses; import android.net.IpPrefix; import android.net.MacAddress; @@ -38,6 +39,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.math.BigInteger; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; @@ -74,6 +77,11 @@ public class StructTest { (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06, }; + private static final Inet4Address TEST_IPV4_ADDRESS = + (Inet4Address) InetAddresses.parseNumericAddress("192.168.100.1"); + private static final Inet6Address TEST_IPV6_ADDRESS = + (Inet6Address) InetAddresses.parseNumericAddress("2001:db8:3:4:5:6:7:8"); + private T doParsingMessageTest(final String hexString, final Class clazz, final ByteOrder order) { final ByteBuffer buf = toByteBuffer(hexString); @@ -733,6 +741,41 @@ public class StructTest { assertArrayEquals(toByteBuffer(hexString).array(), msg.writeToBytes()); } + static class IpAddressMessage extends Struct { + @Field(order = 0, type = Type.Ipv4Address) public final Inet4Address ipv4Address; + @Field(order = 1, type = Type.Ipv6Address) public final Inet6Address ipv6Address; + + IpAddressMessage(final Inet4Address ipv4Address, final Inet6Address ipv6Address) { + this.ipv4Address = ipv4Address; + this.ipv6Address = ipv6Address; + } + } + + @Test + public void testIpAddressType() { + final IpAddressMessage msg = doParsingMessageTest("c0a86401" + + "20010db8000300040005000600070008", IpAddressMessage.class, ByteOrder.BIG_ENDIAN); + + assertEquals(TEST_IPV4_ADDRESS, msg.ipv4Address); + assertEquals(TEST_IPV6_ADDRESS, msg.ipv6Address); + + assertEquals(20, Struct.getSize(IpAddressMessage.class)); + assertArrayEquals(toByteBuffer("c0a86401" + "20010db8000300040005000600070008").array(), + msg.writeToBytes(ByteOrder.BIG_ENDIAN)); + } + + static class WrongIpAddressType extends Struct { + @Field(order = 0, type = Type.Ipv4Address) public byte[] ipv4Address; + @Field(order = 1, type = Type.Ipv6Address) public byte[] ipv6Address; + } + + @Test + public void testIncorrectType_IpAddressWithByteArray() { + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(WrongIpAddressType.class, + toByteBuffer("c0a86401" + "20010db8000300040005000600070008"))); + } + static class FullTypeMessage extends Struct { @Field(order = 0, type = Type.U8) public final short u8; @Field(order = 1, type = Type.U16) public final int u16; @@ -749,11 +792,14 @@ public class StructTest { @Field(order = 12, type = Type.UBE64) public final BigInteger ube64; @Field(order = 13, type = Type.ByteArray, arraysize = 12) public final byte[] bytes; @Field(order = 14, type = Type.EUI48) public final MacAddress eui48; + @Field(order = 15, type = Type.Ipv4Address) public final Inet4Address ipv4Address; + @Field(order = 16, type = Type.Ipv6Address) public final Inet6Address ipv6Address; FullTypeMessage(final short u8, final int u16, final long u32, final long u63, final BigInteger u64, final byte s8, final short s16, final int s32, final long s64, final int ube16, final long ube32, final long ube63, final BigInteger ube64, - final byte[] bytes, final MacAddress eui48) { + final byte[] bytes, final MacAddress eui48, final Inet4Address ipv4Address, + final Inet6Address ipv6Address) { this.u8 = u8; this.u16 = u16; this.u32 = u32; @@ -769,25 +815,40 @@ public class StructTest { this.ube64 = ube64; this.bytes = bytes; this.eui48 = eui48; + this.ipv4Address = ipv4Address; + this.ipv6Address = ipv6Address; } } private static final String FULL_TYPE_DATA = "ff" + "ffff" + "ffffffff" + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + "7fffffffffffffff" + "7fff" + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff" + "20010db80003000400050006" - + "001122334455"; + + "001122334455" + "c0a86401" + "20010db8000300040005000600070008"; private static final String FULL_TYPE_DATA_DIFF_MAC = "ff" + "ffff" + "ffffffff" + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + "7fffffffffffffff" + "7fff" + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff" - + "20010db80003000400050006" + "112233445566"; + + "20010db80003000400050006" + "112233445566" + + "c0a86401" + "20010db8000300040005000600070008"; private static final String FULL_TYPE_DATA_DIFF_LONG = "ff" + "ffff" + "ffffffff" + "7ffffffffffffffe" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + "7fffffffffffffff" + "7fff" + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff" - + "20010db80003000400050006" + "001122334455"; + + "20010db80003000400050006" + "001122334455" + + "c0a86401" + "20010db8000300040005000600070008"; private static final String FULL_TYPE_DATA_DIFF_INTEGER = "ff" + "ffff" + "ffffffff" + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + "7fffffffffffffff" + "7fff" + "ffffff7f" + "7fffffffffffffff" + "ffffffffffffffff" - + "20010db80003000400050006" + "001122334455"; + + "20010db80003000400050006" + "001122334455" + + "c0a86401" + "20010db8000300040005000600070008"; + private static final String FULL_TYPE_DATA_DIFF_IPV4 = "ff" + "ffff" + "ffffffff" + + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + + "7fffffffffffffff" + "7fff" + "ffffff7f" + "7fffffffffffffff" + "ffffffffffffffff" + + "20010db80003000400050006" + "001122334455" + + "c0a81010" + "20010db8000300040005000600070008"; + private static final String FULL_TYPE_DATA_DIFF_IPV6 = "ff" + "ffff" + "ffffffff" + + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + + "7fffffffffffffff" + "7fff" + "ffffff7f" + "7fffffffffffffff" + "ffffffffffffffff" + + "20010db80003000400050006" + "001122334455" + + "c0a86401" + "20010db800030004000500060007000a"; @Test public void testStructClass_equals() { final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class, @@ -808,8 +869,10 @@ public class StructTest { assertEquals(new BigInteger("18446744073709551615"), msg.ube64); assertArrayEquals(TEST_PREFIX64, msg.bytes); assertEquals(MacAddress.fromString("00:11:22:33:44:55"), msg.eui48); + assertEquals(TEST_IPV4_ADDRESS, msg.ipv4Address); + assertEquals(TEST_IPV6_ADDRESS, msg.ipv6Address); - assertEquals(78, msg.getSize(FullTypeMessage.class)); + assertEquals(98, msg.getSize(FullTypeMessage.class)); assertArrayEquals(toByteBuffer(FULL_TYPE_DATA).array(), msg.writeToBytes(ByteOrder.BIG_ENDIAN)); @@ -818,7 +881,7 @@ public class StructTest { new BigInteger("18446744073709551615"), (byte) 0x7f, (short) 0x7fff, (int) 0x7fffffff, (long) 0x7fffffffffffffffL, (int) 0x7fff, (long) 0x7fffffffL, (long) 0x7fffffffffffffffL, new BigInteger("18446744073709551615"), TEST_PREFIX64, - MacAddress.fromString("00:11:22:33:44:55")); + MacAddress.fromString("00:11:22:33:44:55"), TEST_IPV4_ADDRESS, TEST_IPV6_ADDRESS); assertTrue(msg.equals(msg1)); } @@ -838,11 +901,14 @@ public class StructTest { @Field(order = 12, type = Type.UBE64) public final BigInteger ube64; @Field(order = 13, type = Type.ByteArray, arraysize = 12) public final byte[] bytes; @Field(order = 14, type = Type.EUI48) public final MacAddress eui48; + @Field(order = 15, type = Type.Ipv4Address) public final Inet4Address ipv4Address; + @Field(order = 16, type = Type.Ipv6Address) public final Inet6Address ipv6Address; FullTypeMessageWithDupType(final short u8, final int u16, final long u32, final long u63, final BigInteger u64, final byte s8, final short s16, final int s32, final long s64, final int ube16, final long ube32, final long ube63, final BigInteger ube64, - final byte[] bytes, final MacAddress eui48) { + final byte[] bytes, final MacAddress eui48, final Inet4Address ipv4Address, + final Inet6Address ipv6Address) { this.u8 = u8; this.u16 = u16; this.u32 = u32; @@ -858,6 +924,8 @@ public class StructTest { this.ube64 = ube64; this.bytes = bytes; this.eui48 = eui48; + this.ipv4Address = ipv4Address; + this.ipv6Address = ipv6Address; } } @@ -900,6 +968,17 @@ public class StructTest { assertNotEquals(msg.ube32, msg4.ube32); assertFalse(msg.equals(msg4)); + // With different IPv4 address. + final FullTypeMessage msg5 = doParsingMessageTest(FULL_TYPE_DATA_DIFF_IPV4, + FullTypeMessage.class, ByteOrder.BIG_ENDIAN); + assertNotEquals(msg.ipv4Address, msg5.ipv4Address); + assertFalse(msg.equals(msg5)); + + // With different IPv6 address. + final FullTypeMessage msg6 = doParsingMessageTest(FULL_TYPE_DATA_DIFF_IPV6, + FullTypeMessage.class, ByteOrder.BIG_ENDIAN); + assertNotEquals(msg.ipv6Address, msg6.ipv6Address); + assertFalse(msg.equals(msg6)); } @Test @@ -909,7 +988,9 @@ public class StructTest { + " s32: 2147483647, s64: 9223372036854775807, ube16: 32767, ube32: 2147483647," + " ube63: 9223372036854775807, ube64: 18446744073709551615," + " bytes: 0x20010DB80003000400050006," - + " eui48: 00:11:22:33:44:55"; + + " eui48: 00:11:22:33:44:55," + + " ipv4Address: 192.168.100.1," + + " ipv6Address: 2001:db8:3:4:5:6:7:8"; final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class, ByteOrder.BIG_ENDIAN); @@ -922,14 +1003,15 @@ public class StructTest { + " u63: 9223372036854775807, u64: null, s8: 127, s16: 32767," + " s32: 2147483647, s64: 9223372036854775807, ube16: 32767, ube32: 2147483647," + " ube63: 9223372036854775807, ube64: 18446744073709551615," - + " bytes: null, eui48: null"; + + " bytes: null, eui48: null, ipv4Address: 192.168.100.1," + + " ipv6Address: null"; final FullTypeMessage msg = new FullTypeMessage((short) 0xff, (int) 0xffff, (long) 0xffffffffL, (long) 0x7fffffffffffffffL, null /* u64 */, (byte) 0x7f, (short) 0x7fff, (int) 0x7fffffff, (long) 0x7fffffffffffffffL, (int) 0x7fff, (long) 0x7fffffffL, (long) 0x7fffffffffffffffL, new BigInteger("18446744073709551615"), - null /* bytes */, null /* eui48 */); + null /* bytes */, null /* eui48 */, TEST_IPV4_ADDRESS, null /* ipv6Address */); assertEquals(expected, msg.toString()); }