Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b0196a7 authored by Erik Kline's avatar Erik Kline Committed by Android (Google) Code Review
Browse files

Merge "Add IpReachabilityMonitor#probeAll() to begin doing DNAv4/v6-like probing" into mnc-dev

parents f9a0d44d 9ce5d602
Loading
Loading
Loading
Loading
+47 −7
Original line number Original line Diff line number Diff line
@@ -75,7 +75,6 @@ public class IpReachabilityMonitor {
    private boolean mRunning;
    private boolean mRunning;
    final private Thread mObserverThread;
    final private Thread mObserverThread;


    // TODO: consider passing in a NetworkInterface object from the caller.
    public IpReachabilityMonitor(String ifName, Callback callback) throws IllegalArgumentException {
    public IpReachabilityMonitor(String ifName, Callback callback) throws IllegalArgumentException {
        mInterfaceName = ifName;
        mInterfaceName = ifName;
        int ifIndex = -1;
        int ifIndex = -1;
@@ -154,6 +153,12 @@ public class IpReachabilityMonitor {
        }
        }
    }
    }


    private boolean stillRunning() {
        synchronized (mLock) {
            return mRunning;
        }
    }

    public void updateLinkProperties(LinkProperties lp) {
    public void updateLinkProperties(LinkProperties lp) {
        if (!mInterfaceName.equals(lp.getInterfaceName())) {
        if (!mInterfaceName.equals(lp.getInterfaceName())) {
            // TODO: figure out how to cope with interface changes.
            // 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 final class NetlinkSocketObserver implements Runnable {
        private static final String TAG = "NetlinkSocketObserver";
        private static final String TAG = "NetlinkSocketObserver";
@@ -242,12 +288,6 @@ public class IpReachabilityMonitor {
            if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
            if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
        }
        }


        private boolean stillRunning() {
            synchronized (mLock) {
                return mRunning;
            }
        }

        private void clearNetlinkSocket() {
        private void clearNetlinkSocket() {
            if (mSocket != null) {
            if (mSocket != null) {
                mSocket.close();
                mSocket.close();
+65 −0
Original line number Original line Diff line number Diff line
@@ -21,9 +21,11 @@ import android.net.netlink.StructNdMsg;
import android.net.netlink.StructNlAttr;
import android.net.netlink.StructNlAttr;
import android.net.netlink.StructNlMsgHdr;
import android.net.netlink.StructNlMsgHdr;
import android.net.netlink.NetlinkMessage;
import android.net.netlink.NetlinkMessage;
import android.system.OsConstants;
import android.util.Log;
import android.util.Log;


import java.net.InetAddress;
import java.net.InetAddress;
import java.net.Inet6Address;
import java.nio.ByteBuffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ByteOrder;


@@ -131,6 +133,34 @@ public class RtNetlinkNeighborMessage extends NetlinkMessage {
        return bytes;
        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 StructNdMsg mNdmsg;
    private InetAddress mDestination;
    private InetAddress mDestination;
    private byte[] mLinkLayerAddr;
    private byte[] mLinkLayerAddr;
@@ -166,6 +196,41 @@ public class RtNetlinkNeighborMessage extends NetlinkMessage {
        return mCacheInfo;
        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
    @Override
    public String toString() {
    public String toString() {
        final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
        final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
+1 −4
Original line number Original line Diff line number Diff line
@@ -123,9 +123,7 @@ public class StructNdMsg {
        ndm_family = (byte) OsConstants.AF_UNSPEC;
        ndm_family = (byte) OsConstants.AF_UNSPEC;
    }
    }


    public boolean pack(ByteBuffer byteBuffer) {
    public void pack(ByteBuffer byteBuffer) {
        if (!hasAvailableSpace(byteBuffer)) { return false; }

        // The ByteOrder must have already been set by the caller.  In most
        // The ByteOrder must have already been set by the caller.  In most
        // cases ByteOrder.nativeOrder() is correct, with the exception
        // cases ByteOrder.nativeOrder() is correct, with the exception
        // of usage within unittests.
        // of usage within unittests.
@@ -136,7 +134,6 @@ public class StructNdMsg {
        byteBuffer.putShort(ndm_state);
        byteBuffer.putShort(ndm_state);
        byteBuffer.put(ndm_flags);
        byteBuffer.put(ndm_flags);
        byteBuffer.put(ndm_type);
        byteBuffer.put(ndm_type);
        return true;
    }
    }


    public boolean nudConnected() {
    public boolean nudConnected() {
+8 −0
Original line number Original line Diff line number Diff line
@@ -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
    @Override
    public String toString() {
    public String toString() {
        return "StructNlAttr{ "
        return "StructNlAttr{ "
+1 −4
Original line number Original line Diff line number Diff line
@@ -57,9 +57,7 @@ public class StructNlMsgErr {
        msg = null;
        msg = null;
    }
    }


    public boolean pack(ByteBuffer byteBuffer) {
    public void pack(ByteBuffer byteBuffer) {
        if (!hasAvailableSpace(byteBuffer)) { return false; }

        // The ByteOrder must have already been set by the caller.  In most
        // The ByteOrder must have already been set by the caller.  In most
        // cases ByteOrder.nativeOrder() is correct, with the possible
        // cases ByteOrder.nativeOrder() is correct, with the possible
        // exception of usage within unittests.
        // exception of usage within unittests.
@@ -67,7 +65,6 @@ public class StructNlMsgErr {
        if (msg != null) {
        if (msg != null) {
            msg.pack(byteBuffer);
            msg.pack(byteBuffer);
        }
        }
        return true;
    }
    }


    @Override
    @Override
Loading