Merge "Add IpReachabilityMonitor#probeAll() to begin doing DNAv4/v6-like probing" into mnc-dev
This commit is contained in:
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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() {
|
||||
|
@ -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{ "
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user