summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorErik Kline <ek@google.com>2015-05-16 21:10:29 +0900
committerErik Kline <ek@google.com>2015-05-19 09:04:18 +0900
commit9ce5d602cd5d732ae10efe0b648b43ddf60d65c9 (patch)
treeed0eb3cd31d99ffba64856022c40cb2d0c5115b6 /core
parent63b007e651f7b487b09f42f13fe03e0327edea6f (diff)
downloadframeworks_base-9ce5d602cd5d732ae10efe0b648b43ddf60d65c9.zip
frameworks_base-9ce5d602cd5d732ae10efe0b648b43ddf60d65c9.tar.gz
frameworks_base-9ce5d602cd5d732ae10efe0b648b43ddf60d65c9.tar.bz2
Add IpReachabilityMonitor#probeAll() to begin doing DNAv4/v6-like probing
Note that this change is not sufficient to force probing in all cases, but does cause probing to occur on Linux if the target node hasn't been confirmed as reachable in the past 5 seconds (delay_first_probe_time). Bug: 18581716 Bug: 19866451 Bug: 20944464 Change-Id: I29393897118311b48c966c41e2cddb7a784f136f
Diffstat (limited to 'core')
-rw-r--r--core/java/android/net/IpReachabilityMonitor.java54
-rw-r--r--core/java/android/net/netlink/RtNetlinkNeighborMessage.java65
-rw-r--r--core/java/android/net/netlink/StructNdMsg.java5
-rw-r--r--core/java/android/net/netlink/StructNlAttr.java8
-rw-r--r--core/java/android/net/netlink/StructNlMsgErr.java5
-rw-r--r--core/java/android/net/netlink/StructNlMsgHdr.java11
-rw-r--r--core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java52
7 files changed, 178 insertions, 22 deletions
diff --git a/core/java/android/net/IpReachabilityMonitor.java b/core/java/android/net/IpReachabilityMonitor.java
index 7e1c05b..add8774 100644
--- a/core/java/android/net/IpReachabilityMonitor.java
+++ b/core/java/android/net/IpReachabilityMonitor.java
@@ -75,7 +75,6 @@ public class IpReachabilityMonitor {
private boolean mRunning;
final private Thread mObserverThread;
- // TODO: consider passing in a NetworkInterface object from the caller.
public IpReachabilityMonitor(String ifName, Callback callback) throws IllegalArgumentException {
mInterfaceName = ifName;
int ifIndex = -1;
@@ -154,6 +153,12 @@ public class IpReachabilityMonitor {
}
}
+ private boolean stillRunning() {
+ synchronized (mLock) {
+ return mRunning;
+ }
+ }
+
public void updateLinkProperties(LinkProperties lp) {
if (!mInterfaceName.equals(lp.getInterfaceName())) {
// TODO: figure out how to cope with interface changes.
@@ -204,6 +209,47 @@ public class IpReachabilityMonitor {
}
}
+ public void probeAll() {
+ Set<InetAddress> ipProbeList = new HashSet<InetAddress>();
+ synchronized (mLock) {
+ ipProbeList.addAll(mIpWatchList);
+ }
+ for (InetAddress target : ipProbeList) {
+ if (!stillRunning()) { break; }
+ probeIp(target);
+ }
+ }
+
+ private void probeIp(InetAddress ip) {
+ // This currently does not cause neighbor probing if the target |ip|
+ // has been confirmed reachable within the past "delay_probe_time"
+ // seconds, i.e. within the past 5 seconds.
+ //
+ // TODO: replace with a transition directly to NUD_PROBE state once
+ // kernels are updated to do so correctly.
+ if (DBG) { Log.d(TAG, "Probing ip=" + ip.getHostAddress()); }
+
+ final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
+ 1, ip, StructNdMsg.NUD_DELAY, mInterfaceIndex, null);
+ NetlinkSocket nlSocket = null;
+
+ try {
+ nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
+ nlSocket.connectToKernel();
+ nlSocket.sendMessage(msg, 0, msg.length, 300);
+ final NetlinkMessage response = NetlinkMessage.parse(nlSocket.recvMessage(300));
+ if (response != null && response instanceof NetlinkErrorMessage) {
+ Log.e(TAG, "Error probing ip=" + response.toString());
+ }
+ } catch (ErrnoException | InterruptedIOException | SocketException e) {
+ Log.d(TAG, "Error probing ip=" + ip.getHostAddress(), e);
+ }
+
+ if (nlSocket != null) {
+ nlSocket.close();
+ }
+ }
+
private final class NetlinkSocketObserver implements Runnable {
private static final String TAG = "NetlinkSocketObserver";
@@ -242,12 +288,6 @@ public class IpReachabilityMonitor {
if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
}
- private boolean stillRunning() {
- synchronized (mLock) {
- return mRunning;
- }
- }
-
private void clearNetlinkSocket() {
if (mSocket != null) {
mSocket.close();
diff --git a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java b/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
index d4b572c..b5f5817 100644
--- a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
+++ b/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
@@ -21,9 +21,11 @@ import android.net.netlink.StructNdMsg;
import android.net.netlink.StructNlAttr;
import android.net.netlink.StructNlMsgHdr;
import android.net.netlink.NetlinkMessage;
+import android.system.OsConstants;
import android.util.Log;
import java.net.InetAddress;
+import java.net.Inet6Address;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -131,6 +133,34 @@ public class RtNetlinkNeighborMessage extends NetlinkMessage {
return bytes;
}
+ /**
+ * A convenience method to create an RTM_NEWNEIGH message, to modify
+ * the kernel's state information for a specific neighbor.
+ */
+ public static byte[] newNewNeighborMessage(
+ int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) {
+ final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
+ nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH;
+ nlmsghdr.nlmsg_flags = StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_REPLACE;
+ nlmsghdr.nlmsg_seq = seqNo;
+
+ final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr);
+ msg.mNdmsg = new StructNdMsg();
+ msg.mNdmsg.ndm_family =
+ (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
+ msg.mNdmsg.ndm_ifindex = ifIndex;
+ msg.mNdmsg.ndm_state = nudState;
+ msg.mDestination = ip;
+ msg.mLinkLayerAddr = llAddr; // might be null
+
+ final byte[] bytes = new byte[msg.getRequiredSpace()];
+ nlmsghdr.nlmsg_len = bytes.length;
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+ byteBuffer.order(ByteOrder.nativeOrder());
+ msg.pack(byteBuffer);
+ return bytes;
+ }
+
private StructNdMsg mNdmsg;
private InetAddress mDestination;
private byte[] mLinkLayerAddr;
@@ -166,6 +196,41 @@ public class RtNetlinkNeighborMessage extends NetlinkMessage {
return mCacheInfo;
}
+ public int getRequiredSpace() {
+ int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
+ if (mDestination != null) {
+ spaceRequired += NetlinkConstants.alignedLengthOf(
+ StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length);
+ }
+ if (mLinkLayerAddr != null) {
+ spaceRequired += NetlinkConstants.alignedLengthOf(
+ StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length);
+ }
+ // Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO
+ // attributes appended. Fix later, if necessary.
+ return spaceRequired;
+ }
+
+ private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) {
+ final StructNlAttr nlAttr = new StructNlAttr();
+ nlAttr.nla_type = nlType;
+ nlAttr.nla_value = nlValue;
+ nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length);
+ nlAttr.pack(byteBuffer);
+ }
+
+ public void pack(ByteBuffer byteBuffer) {
+ getHeader().pack(byteBuffer) ;
+ mNdmsg.pack(byteBuffer);
+
+ if (mDestination != null) {
+ packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer);
+ }
+ if (mLinkLayerAddr != null) {
+ packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer);
+ }
+ }
+
@Override
public String toString() {
final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
diff --git a/core/java/android/net/netlink/StructNdMsg.java b/core/java/android/net/netlink/StructNdMsg.java
index e66d45d..ca1cbbb 100644
--- a/core/java/android/net/netlink/StructNdMsg.java
+++ b/core/java/android/net/netlink/StructNdMsg.java
@@ -123,9 +123,7 @@ public class StructNdMsg {
ndm_family = (byte) OsConstants.AF_UNSPEC;
}
- public boolean pack(ByteBuffer byteBuffer) {
- if (!hasAvailableSpace(byteBuffer)) { return false; }
-
+ public void pack(ByteBuffer byteBuffer) {
// The ByteOrder must have already been set by the caller. In most
// cases ByteOrder.nativeOrder() is correct, with the exception
// of usage within unittests.
@@ -136,7 +134,6 @@ public class StructNdMsg {
byteBuffer.putShort(ndm_state);
byteBuffer.put(ndm_flags);
byteBuffer.put(ndm_type);
- return true;
}
public boolean nudConnected() {
diff --git a/core/java/android/net/netlink/StructNlAttr.java b/core/java/android/net/netlink/StructNlAttr.java
index 9aef4c7..597a6aa 100644
--- a/core/java/android/net/netlink/StructNlAttr.java
+++ b/core/java/android/net/netlink/StructNlAttr.java
@@ -116,6 +116,14 @@ public class StructNlAttr {
}
}
+ public void pack(ByteBuffer byteBuffer) {
+ final int originalPosition = byteBuffer.position();
+ byteBuffer.putShort(nla_len);
+ byteBuffer.putShort(nla_type);
+ byteBuffer.put(nla_value);
+ byteBuffer.position(originalPosition + getAlignedLength());
+ }
+
@Override
public String toString() {
return "StructNlAttr{ "
diff --git a/core/java/android/net/netlink/StructNlMsgErr.java b/core/java/android/net/netlink/StructNlMsgErr.java
index 5da19a2..6b02650 100644
--- a/core/java/android/net/netlink/StructNlMsgErr.java
+++ b/core/java/android/net/netlink/StructNlMsgErr.java
@@ -57,9 +57,7 @@ public class StructNlMsgErr {
msg = null;
}
- public boolean pack(ByteBuffer byteBuffer) {
- if (!hasAvailableSpace(byteBuffer)) { return false; }
-
+ public void pack(ByteBuffer byteBuffer) {
// The ByteOrder must have already been set by the caller. In most
// cases ByteOrder.nativeOrder() is correct, with the possible
// exception of usage within unittests.
@@ -67,7 +65,6 @@ public class StructNlMsgErr {
if (msg != null) {
msg.pack(byteBuffer);
}
- return true;
}
@Override
diff --git a/core/java/android/net/netlink/StructNlMsgHdr.java b/core/java/android/net/netlink/StructNlMsgHdr.java
index 67925ac..98ab5e7 100644
--- a/core/java/android/net/netlink/StructNlMsgHdr.java
+++ b/core/java/android/net/netlink/StructNlMsgHdr.java
@@ -39,6 +39,12 @@ public class StructNlMsgHdr {
public static final short NLM_F_ROOT = 0x0100;
public static final short NLM_F_MATCH = 0x0200;
public static final short NLM_F_DUMP = NLM_F_ROOT|NLM_F_MATCH;
+ // Flags for a NEW request.
+ public static final short NLM_F_REPLACE = 0x100;
+ public static final short NLM_F_EXCL = 0x200;
+ public static final short NLM_F_CREATE = 0x400;
+ public static final short NLM_F_APPEND = 0x800;
+
public static String stringForNlMsgFlags(short flags) {
final StringBuilder sb = new StringBuilder();
@@ -106,9 +112,7 @@ public class StructNlMsgHdr {
nlmsg_pid = 0;
}
- public boolean pack(ByteBuffer byteBuffer) {
- if (!hasAvailableSpace(byteBuffer)) { return false; }
-
+ public void pack(ByteBuffer byteBuffer) {
// The ByteOrder must have already been set by the caller. In most
// cases ByteOrder.nativeOrder() is correct, with the possible
// exception of usage within unittests.
@@ -117,7 +121,6 @@ public class StructNlMsgHdr {
byteBuffer.putShort(nlmsg_flags);
byteBuffer.putInt(nlmsg_seq);
byteBuffer.putInt(nlmsg_pid);
- return true;
}
@Override
diff --git a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
index 0634281..a7bebad 100644
--- a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ b/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
@@ -26,9 +26,11 @@ import android.util.Log;
import libcore.util.HexEncoding;
import java.net.InetAddress;
+import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Arrays;
import junit.framework.TestCase;
@@ -133,7 +135,7 @@ public class RtNetlinkNeighborMessageTest extends TestCase {
public static final byte[] RTM_GETNEIGH_RESPONSE =
HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
- public void testParseRtNetlinkNeighborRtmDelNeigh() {
+ public void testParseRtmDelNeigh() {
final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
@@ -159,7 +161,7 @@ public class RtNetlinkNeighborMessageTest extends TestCase {
assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
}
- public void testParseRtNetlinkNeighborRtmNewNeigh() {
+ public void testParseRtmNewNeigh() {
final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
@@ -185,7 +187,7 @@ public class RtNetlinkNeighborMessageTest extends TestCase {
assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
}
- public void testParseRtNetlinkNeighborRtmGetNeighResponse() {
+ public void testParseRtmGetNeighResponse() {
final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
@@ -208,4 +210,48 @@ public class RtNetlinkNeighborMessageTest extends TestCase {
// TODO: add more detailed spot checks.
assertEquals(14, messageCount);
}
+
+ public void testCreateRtmNewNeighMessage() {
+ final int seqNo = 2635;
+ final int ifIndex = 14;
+ final byte[] llAddr =
+ new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6 };
+
+ // Hexadecimal representation of our created packet.
+ final String expectedNewNeighHex =
+ // struct nlmsghdr
+ "30000000" + // length = 48
+ "1c00" + // type = 28 (RTM_NEWNEIGH)
+ "0101" + // flags (NLM_F_REQUEST | NLM_F_REPLACE)
+ "4b0a0000" + // seqno
+ "00000000" + // pid (0 == kernel)
+ // struct ndmsg
+ "02" + // family
+ "00" + // pad1
+ "0000" + // pad2
+ "0e000000" + // interface index (14)
+ "0800" + // NUD state (0x08 == NUD_DELAY)
+ "00" + // flags
+ "00" + // type
+ // struct nlattr: NDA_DST
+ "0800" + // length = 8
+ "0100" + // type (1 == NDA_DST, for neighbor messages)
+ "7f000001" + // IPv4 address (== 127.0.0.1)
+ // struct nlattr: NDA_LLADDR
+ "0a00" + // length = 10
+ "0200" + // type (2 == NDA_LLADDR, for neighbor messages)
+ "010203040506" + // MAC Address (== 01:02:03:04:05:06)
+ "0000"; // padding, for 4 byte alignment
+ final byte[] expectedNewNeigh =
+ HexEncoding.decode(expectedNewNeighHex.toCharArray(), false);
+
+ final byte[] bytes = RtNetlinkNeighborMessage.newNewNeighborMessage(
+ seqNo, Inet4Address.LOOPBACK, StructNdMsg.NUD_DELAY, ifIndex, llAddr);
+ if (!Arrays.equals(expectedNewNeigh, bytes)) {
+ assertEquals(expectedNewNeigh.length, bytes.length);
+ for (int i = 0; i < Math.min(expectedNewNeigh.length, bytes.length); i++) {
+ assertEquals(expectedNewNeigh[i], bytes[i]);
+ }
+ }
+ }
}