Remove the concept of byte order from StructNlAttr.

Structures don't have byte orders, only fields have byte orders.
StructNlAttr stores a byte order internally to support netlink
attributes that contain only an iteger.

This is not really a common use case. Also, continuing to store
the byte order inside StructNlAttr means that when parsing
nested structures, the byte order needs to be passed to peek()
and findNextAttrOfType. This is very clunky given that most
attributes won't have an endianness.

Instead, remove the concept of byte order from the object
altogether. If a caller wants to read a StructNlAttr that
contains an integer, they must now call different methods
depending on whether the integer is big endian or native
order.

Callers that want to create a StructNlAttr from an integer of
known byte order already meeded to specify that order when
constructing the object, and this does not change.

Test: atest NetworkStackNextTests
Change-Id: I97345d29529e087e94c86ee82af06e371876d7cc
diff --git a/common/netlinkclient/src/android/net/netlink/StructNlAttr.java b/common/netlinkclient/src/android/net/netlink/StructNlAttr.java
index 747998d..59458c1 100644
--- a/common/netlinkclient/src/android/net/netlink/StructNlAttr.java
+++ b/common/netlinkclient/src/android/net/netlink/StructNlAttr.java
@@ -18,8 +18,8 @@
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
-import java.nio.ByteOrder;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 
 
 /**
@@ -48,9 +48,7 @@
         }
         final int baseOffset = byteBuffer.position();
 
-        // Assume the byte order of the buffer is the expected byte order of the value.
-        final StructNlAttr struct = new StructNlAttr(byteBuffer.order());
-        // The byte order of nla_len and nla_type is always native.
+        final StructNlAttr struct = new StructNlAttr();
         final ByteOrder originalOrder = byteBuffer.order();
         byteBuffer.order(ByteOrder.nativeOrder());
         try {
@@ -91,16 +89,8 @@
     public short nla_type;
     public byte[] nla_value;
 
-    // The byte order used to read/write the value member. Netlink length and
-    // type members are always read/written in native order.
-    private ByteOrder mByteOrder = ByteOrder.nativeOrder();
-
     public StructNlAttr() {}
 
-    public StructNlAttr(ByteOrder byteOrder) {
-        mByteOrder = byteOrder;
-    }
-
     public StructNlAttr(short type, byte value) {
         nla_type = type;
         setValue(new byte[1]);
@@ -112,10 +102,16 @@
     }
 
     public StructNlAttr(short type, short value, ByteOrder order) {
-        this(order);
         nla_type = type;
         setValue(new byte[Short.BYTES]);
-        getValueAsByteBuffer().putShort(value);
+        final ByteBuffer buf = getValueAsByteBuffer();
+        final ByteOrder originalOrder = buf.order();
+        try {
+            buf.order(order);
+            buf.putShort(value);
+        } finally {
+            buf.order(originalOrder);
+        }
     }
 
     public StructNlAttr(short type, int value) {
@@ -123,10 +119,16 @@
     }
 
     public StructNlAttr(short type, int value, ByteOrder order) {
-        this(order);
         nla_type = type;
         setValue(new byte[Integer.BYTES]);
-        getValueAsByteBuffer().putInt(value);
+        final ByteBuffer buf = getValueAsByteBuffer();
+        final ByteOrder originalOrder = buf.order();
+        try {
+            buf.order(order);
+            buf.putInt(value);
+        } finally {
+            buf.order(originalOrder);
+        }
     }
 
     public StructNlAttr(short type, InetAddress ip) {
@@ -152,10 +154,27 @@
         return NetlinkConstants.alignedLengthOf(nla_len);
     }
 
+    public int getValueAsBe32(int defaultValue) {
+        final ByteBuffer byteBuffer = getValueAsByteBuffer();
+        if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
+            return defaultValue;
+        }
+        final ByteOrder originalOrder = byteBuffer.order();
+        try {
+            byteBuffer.order(ByteOrder.BIG_ENDIAN);
+            return byteBuffer.getInt();
+        } finally {
+            byteBuffer.order(originalOrder);
+        }
+    }
+
     public ByteBuffer getValueAsByteBuffer() {
         if (nla_value == null) { return null; }
         final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value);
-        byteBuffer.order(mByteOrder);
+        // By convention, all buffers in this library are in native byte order because netlink is in
+        // native byte order. It's the order that is used by NetlinkSocket.recvMessage and the only
+        // order accepted by NetlinkMessage.parse.
+        byteBuffer.order(ByteOrder.nativeOrder());
         return byteBuffer;
     }
 
diff --git a/tests/unit/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/tests/unit/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
index c3f9068..a1f1d44 100644
--- a/tests/unit/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ b/tests/unit/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
@@ -151,6 +151,13 @@
             assertEquals(0, hdr.nlmsg_seq);
             assertEquals(11070, hdr.nlmsg_pid);
 
+            final int probes = neighMsg.getProbes();
+            assertTrue("Unexpected number of probes. Got " +  probes + ", max=5",
+                    probes < 5);
+            final int ndm_refcnt = neighMsg.getCacheInfo().ndm_refcnt;
+            assertTrue("nda_cacheinfo has unexpectedly high ndm_refcnt: " + ndm_refcnt,
+                    ndm_refcnt < 0x100);
+
             messageCount++;
         }
         // TODO: add more detailed spot checks.