diff options
| author | Erik Kline <ek@google.com> | 2015-05-16 21:10:29 +0900 |
|---|---|---|
| committer | Erik Kline <ek@google.com> | 2015-05-19 09:04:18 +0900 |
| commit | 9ce5d602cd5d732ae10efe0b648b43ddf60d65c9 (patch) | |
| tree | ed0eb3cd31d99ffba64856022c40cb2d0c5115b6 /core | |
| parent | 63b007e651f7b487b09f42f13fe03e0327edea6f (diff) | |
| download | frameworks_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')
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]); + } + } + } } |
