1787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline/*
2787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * Copyright (C) 2015 The Android Open Source Project
3787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline *
4787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * Licensed under the Apache License, Version 2.0 (the "License");
5787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * you may not use this file except in compliance with the License.
6787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * You may obtain a copy of the License at
7787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline *
8787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline *      http://www.apache.org/licenses/LICENSE-2.0
9787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline *
10787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * Unless required by applicable law or agreed to in writing, software
11787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * distributed under the License is distributed on an "AS IS" BASIS,
12787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * See the License for the specific language governing permissions and
14787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * limitations under the License.
15787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline */
16787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
1702cc5a030a6f132e776b754dd5684ae632009f76Erik Klinepackage android.net.ip;
18787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
19b1eebaeb926c698eded5a892484fd9904b36cd69Erik Klineimport com.android.internal.annotations.GuardedBy;
20b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline
2176fde62da7487d60910d3fa025dc6db5971f95d8Erik Klineimport android.content.Context;
22787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.LinkAddress;
23787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.LinkProperties;
24b1eebaeb926c698eded5a892484fd9904b36cd69Erik Klineimport android.net.LinkProperties.ProvisioningChange;
25787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.ProxyInfo;
26787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.RouteInfo;
27cfddd6879283860bb4d2cf2972ea086f585a37ecHugo Benichiimport android.net.metrics.IpConnectivityLog;
2825bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichiimport android.net.metrics.IpReachabilityEvent;
29787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.netlink.NetlinkConstants;
30787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.netlink.NetlinkErrorMessage;
31787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.netlink.NetlinkMessage;
32787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.netlink.NetlinkSocket;
33787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.netlink.RtNetlinkNeighborMessage;
34787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.netlink.StructNdaCacheInfo;
35787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.netlink.StructNdMsg;
36787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.net.netlink.StructNlMsgHdr;
375b437d6ff91116f25be946e07d5d90cd25c372a4Erik Klineimport android.net.util.AvoidBadWifiTracker;
3876fde62da7487d60910d3fa025dc6db5971f95d8Erik Klineimport android.os.PowerManager;
39787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.os.SystemClock;
40787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.system.ErrnoException;
41787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.system.NetlinkSocketAddress;
42787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.system.OsConstants;
43787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport android.util.Log;
44787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
45787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.io.InterruptedIOException;
465b437d6ff91116f25be946e07d5d90cd25c372a4Erik Klineimport java.net.Inet6Address;
47787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.net.InetAddress;
48787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.net.InetSocketAddress;
49787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.net.NetworkInterface;
50787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.net.SocketAddress;
51787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.net.SocketException;
52787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.nio.ByteBuffer;
53787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.util.Arrays;
54787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.util.HashMap;
55787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.util.HashSet;
56787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.util.List;
57b1eebaeb926c698eded5a892484fd9904b36cd69Erik Klineimport java.util.Map;
58787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klineimport java.util.Set;
59787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
60787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
61787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline/**
62787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * IpReachabilityMonitor.
63787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline *
64787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * Monitors on-link IP reachability and notifies callers whenever any on-link
65787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * addresses of interest appear to have become unresponsive.
66787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline *
6741480898f3e98437285455efbb9b64a2c23733dfErik Kline * This code does not concern itself with "why" a neighbour might have become
6841480898f3e98437285455efbb9b64a2c23733dfErik Kline * unreachable. Instead, it primarily reacts to the kernel's notion of IP
6941480898f3e98437285455efbb9b64a2c23733dfErik Kline * reachability for each of the neighbours we know to be critically important
7041480898f3e98437285455efbb9b64a2c23733dfErik Kline * to normal network connectivity. As such, it is often "just the messenger":
7141480898f3e98437285455efbb9b64a2c23733dfErik Kline * the neighbours about which it warns are already deemed by the kernel to have
7241480898f3e98437285455efbb9b64a2c23733dfErik Kline * become unreachable.
7341480898f3e98437285455efbb9b64a2c23733dfErik Kline *
7441480898f3e98437285455efbb9b64a2c23733dfErik Kline *
7541480898f3e98437285455efbb9b64a2c23733dfErik Kline * How it works:
7641480898f3e98437285455efbb9b64a2c23733dfErik Kline *
7741480898f3e98437285455efbb9b64a2c23733dfErik Kline *   1. The "on-link neighbours of interest" found in a given LinkProperties
7841480898f3e98437285455efbb9b64a2c23733dfErik Kline *      instance are added to a "watch list" via #updateLinkProperties().
7941480898f3e98437285455efbb9b64a2c23733dfErik Kline *      This usually means all default gateways and any on-link DNS servers.
8041480898f3e98437285455efbb9b64a2c23733dfErik Kline *
8141480898f3e98437285455efbb9b64a2c23733dfErik Kline *   2. We listen continuously for netlink neighbour messages (RTM_NEWNEIGH,
8241480898f3e98437285455efbb9b64a2c23733dfErik Kline *      RTM_DELNEIGH), watching only for neighbours in the watch list.
8341480898f3e98437285455efbb9b64a2c23733dfErik Kline *
8441480898f3e98437285455efbb9b64a2c23733dfErik Kline *        - A neighbour going into NUD_REACHABLE, NUD_STALE, NUD_DELAY, and
8541480898f3e98437285455efbb9b64a2c23733dfErik Kline *          even NUD_PROBE is perfectly normal; we merely record the new state.
8641480898f3e98437285455efbb9b64a2c23733dfErik Kline *
8741480898f3e98437285455efbb9b64a2c23733dfErik Kline *        - A neighbour's entry may be deleted (RTM_DELNEIGH), for example due
8841480898f3e98437285455efbb9b64a2c23733dfErik Kline *          to garbage collection.  This is not necessarily of immediate
8941480898f3e98437285455efbb9b64a2c23733dfErik Kline *          concern; we record the neighbour as moving to NUD_NONE.
9041480898f3e98437285455efbb9b64a2c23733dfErik Kline *
9141480898f3e98437285455efbb9b64a2c23733dfErik Kline *        - A neighbour transitioning to NUD_FAILED (for any reason) is
9241480898f3e98437285455efbb9b64a2c23733dfErik Kline *          critically important and is handled as described below in #4.
9341480898f3e98437285455efbb9b64a2c23733dfErik Kline *
9441480898f3e98437285455efbb9b64a2c23733dfErik Kline *   3. All on-link neighbours in the watch list can be forcibly "probed" by
9541480898f3e98437285455efbb9b64a2c23733dfErik Kline *      calling #probeAll(). This should be called whenever it is important to
9641480898f3e98437285455efbb9b64a2c23733dfErik Kline *      verify that critical neighbours on the link are still reachable, e.g.
9741480898f3e98437285455efbb9b64a2c23733dfErik Kline *      when roaming between BSSIDs.
9841480898f3e98437285455efbb9b64a2c23733dfErik Kline *
9941480898f3e98437285455efbb9b64a2c23733dfErik Kline *        - The kernel will send unicast ARP requests for IPv4 neighbours and
10041480898f3e98437285455efbb9b64a2c23733dfErik Kline *          unicast NS packets for IPv6 neighbours.  The expected replies will
10141480898f3e98437285455efbb9b64a2c23733dfErik Kline *          likely be unicast.
10241480898f3e98437285455efbb9b64a2c23733dfErik Kline *
10341480898f3e98437285455efbb9b64a2c23733dfErik Kline *        - The forced probing is done holding a wakelock. The kernel may,
10441480898f3e98437285455efbb9b64a2c23733dfErik Kline *          however, initiate probing of a neighbor on its own, i.e. whenever
10541480898f3e98437285455efbb9b64a2c23733dfErik Kline *          a neighbour has expired from NUD_DELAY.
10641480898f3e98437285455efbb9b64a2c23733dfErik Kline *
10741480898f3e98437285455efbb9b64a2c23733dfErik Kline *        - The kernel sends:
10841480898f3e98437285455efbb9b64a2c23733dfErik Kline *
10941480898f3e98437285455efbb9b64a2c23733dfErik Kline *              /proc/sys/net/ipv{4,6}/neigh/<ifname>/ucast_solicit
11041480898f3e98437285455efbb9b64a2c23733dfErik Kline *
11141480898f3e98437285455efbb9b64a2c23733dfErik Kline *          number of probes (usually 3) every:
11241480898f3e98437285455efbb9b64a2c23733dfErik Kline *
11341480898f3e98437285455efbb9b64a2c23733dfErik Kline *              /proc/sys/net/ipv{4,6}/neigh/<ifname>/retrans_time_ms
11441480898f3e98437285455efbb9b64a2c23733dfErik Kline *
11541480898f3e98437285455efbb9b64a2c23733dfErik Kline *          number of milliseconds (usually 1000ms). This normally results in
11641480898f3e98437285455efbb9b64a2c23733dfErik Kline *          3 unicast packets, 1 per second.
11741480898f3e98437285455efbb9b64a2c23733dfErik Kline *
11841480898f3e98437285455efbb9b64a2c23733dfErik Kline *        - If no response is received to any of the probe packets, the kernel
11941480898f3e98437285455efbb9b64a2c23733dfErik Kline *          marks the neighbour as being in state NUD_FAILED, and the listening
12041480898f3e98437285455efbb9b64a2c23733dfErik Kline *          process in #2 will learn of it.
12141480898f3e98437285455efbb9b64a2c23733dfErik Kline *
12241480898f3e98437285455efbb9b64a2c23733dfErik Kline *   4. We call the supplied Callback#notifyLost() function if the loss of a
12341480898f3e98437285455efbb9b64a2c23733dfErik Kline *      neighbour in NUD_FAILED would cause IPv4 or IPv6 configuration to
12441480898f3e98437285455efbb9b64a2c23733dfErik Kline *      become incomplete (a loss of provisioning).
12541480898f3e98437285455efbb9b64a2c23733dfErik Kline *
12641480898f3e98437285455efbb9b64a2c23733dfErik Kline *        - For example, losing all our IPv4 on-link DNS servers (or losing
12741480898f3e98437285455efbb9b64a2c23733dfErik Kline *          our only IPv6 default gateway) constitutes a loss of IPv4 (IPv6)
12841480898f3e98437285455efbb9b64a2c23733dfErik Kline *          provisioning; Callback#notifyLost() would be called.
12941480898f3e98437285455efbb9b64a2c23733dfErik Kline *
13041480898f3e98437285455efbb9b64a2c23733dfErik Kline *        - Since it can be non-trivial to reacquire certain IP provisioning
13141480898f3e98437285455efbb9b64a2c23733dfErik Kline *          state it may be best for the link to disconnect completely and
13241480898f3e98437285455efbb9b64a2c23733dfErik Kline *          reconnect afresh.
13341480898f3e98437285455efbb9b64a2c23733dfErik Kline *
134787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline * @hide
135787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline */
136787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Klinepublic class IpReachabilityMonitor {
137787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    private static final String TAG = "IpReachabilityMonitor";
138f188d41fa2876a4c77586656bce06cac10d08942Joe Onorato    private static final boolean DBG = false;
139787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    private static final boolean VDBG = false;
140787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
141787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    public interface Callback {
142b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        // This callback function must execute as quickly as possible as it is
143b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        // run on the same thread that listens to kernel neighbor updates.
144b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        //
145b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        // TODO: refactor to something like notifyProvisioningLost(String msg).
146787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        public void notifyLost(InetAddress ip, String logMsg);
147787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    }
148787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
149787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    private final Object mLock = new Object();
15076fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline    private final PowerManager.WakeLock mWakeLock;
151787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    private final String mInterfaceName;
152787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    private final int mInterfaceIndex;
153787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    private final Callback mCallback;
1545b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline    private final AvoidBadWifiTracker mAvoidBadWifiTracker;
155abd3142dcae02026689b939c363329b822b7cc0aErik Kline    private final NetlinkSocketObserver mNetlinkSocketObserver;
156abd3142dcae02026689b939c363329b822b7cc0aErik Kline    private final Thread mObserverThread;
157cfddd6879283860bb4d2cf2972ea086f585a37ecHugo Benichi    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
158b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    @GuardedBy("mLock")
159b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    private LinkProperties mLinkProperties = new LinkProperties();
160b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    // TODO: consider a map to a private NeighborState class holding more
161b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    // information than a single NUD state entry.
162b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    @GuardedBy("mLock")
163b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    private Map<InetAddress, Short> mIpWatchList = new HashMap<>();
164b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    @GuardedBy("mLock")
165b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    private int mIpWatchListVersion;
166b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    @GuardedBy("mLock")
167b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    private boolean mRunning;
1680d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi    // Time in milliseconds of the last forced probe request.
1690d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi    private volatile long mLastProbeTimeMs;
170787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
171cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline    /**
17255618be44c5d2a7db3cf23881cace15108f07557Pierre Imai     * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
173cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline     * for the given IP address on the specified interface index.
174cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline     *
17525bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi     * @return 0 if the request was successfully passed to the kernel; otherwise return
17625bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi     *         a non-zero error code.
177cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline     */
17825bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi    private static int probeNeighbor(int ifIndex, InetAddress ip) {
179b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
180b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        if (DBG) { Log.d(TAG, msgSnippet); }
181cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline
182cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline        final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
1832027d85cbe2559a3f12aa2ac70af2b556788ec4cErik Kline                1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
184cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline
18525bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi        int errno = -OsConstants.EPROTO;
186b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        try (NetlinkSocket nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE)) {
18725bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi            final long IO_TIMEOUT = 300L;
188cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline            nlSocket.connectToKernel();
189cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline            nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT);
190cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline            final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT);
19125bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi            // recvMessage() guaranteed to not return null if it did not throw.
192cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline            final NetlinkMessage response = NetlinkMessage.parse(bytes);
193cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline            if (response != null && response instanceof NetlinkErrorMessage &&
19425bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi                    (((NetlinkErrorMessage) response).getNlMsgError() != null)) {
19525bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi                errno = ((NetlinkErrorMessage) response).getNlMsgError().error;
19625bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi                if (errno != 0) {
19725bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi                    // TODO: consider ignoring EINVAL (-22), which appears to be
19825bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi                    // normal when probing a neighbor for which the kernel does
19925bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi                    // not already have / no longer has a link layer address.
20025bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi                    Log.e(TAG, "Error " + msgSnippet + ", errmsg=" + response.toString());
20125bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi                }
202cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline            } else {
203cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline                String errmsg;
20425bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi                if (response == null) {
205cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline                    bytes.position(0);
206cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline                    errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
207cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline                } else {
208cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline                    errmsg = response.toString();
209cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline                }
210b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                Log.e(TAG, "Error " + msgSnippet + ", errmsg=" + errmsg);
211cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline            }
21225bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi        } catch (ErrnoException e) {
21325bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi            Log.e(TAG, "Error " + msgSnippet, e);
21425bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi            errno = -e.errno;
21525bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi        } catch (InterruptedIOException e) {
21625bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi            Log.e(TAG, "Error " + msgSnippet, e);
21725bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi            errno = -OsConstants.ETIMEDOUT;
21825bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi        } catch (SocketException e) {
21925bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi            Log.e(TAG, "Error " + msgSnippet, e);
22025bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi            errno = -OsConstants.EIO;
221cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline        }
22225bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi        return errno;
223cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline    }
224cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline
2255b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline    public IpReachabilityMonitor(Context context, String ifName, Callback callback) {
2265b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline        this(context, ifName, callback, null);
2275b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline    }
2285b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline
2295b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline    public IpReachabilityMonitor(Context context, String ifName, Callback callback,
2305b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline            AvoidBadWifiTracker tracker) throws IllegalArgumentException {
231787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        mInterfaceName = ifName;
232787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        int ifIndex = -1;
233787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        try {
234787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            NetworkInterface netIf = NetworkInterface.getByName(ifName);
235787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            mInterfaceIndex = netIf.getIndex();
236787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        } catch (SocketException | NullPointerException e) {
237787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            throw new IllegalArgumentException("invalid interface '" + ifName + "': ", e);
238787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
23976fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
24076fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline                PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName);
241787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        mCallback = callback;
2425b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline        mAvoidBadWifiTracker = tracker;
243abd3142dcae02026689b939c363329b822b7cc0aErik Kline        mNetlinkSocketObserver = new NetlinkSocketObserver();
244abd3142dcae02026689b939c363329b822b7cc0aErik Kline        mObserverThread = new Thread(mNetlinkSocketObserver);
245787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        mObserverThread.start();
246787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    }
247787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
248787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    public void stop() {
249abd3142dcae02026689b939c363329b822b7cc0aErik Kline        synchronized (mLock) { mRunning = false; }
250abd3142dcae02026689b939c363329b822b7cc0aErik Kline        clearLinkProperties();
251abd3142dcae02026689b939c363329b822b7cc0aErik Kline        mNetlinkSocketObserver.clearNetlinkSocket();
252787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    }
253787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
254787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    // TODO: add a public dump() method that can be called during a bug report.
255787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
256787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    private String describeWatchList() {
257b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        final String delimiter = ", ";
258b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        StringBuilder sb = new StringBuilder();
259787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        synchronized (mLock) {
260b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            sb.append("iface{" + mInterfaceName + "/" + mInterfaceIndex + "}, ");
261b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            sb.append("v{" + mIpWatchListVersion + "}, ");
262b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            sb.append("ntable=[");
263b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            boolean firstTime = true;
264b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            for (Map.Entry<InetAddress, Short> entry : mIpWatchList.entrySet()) {
265b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                if (firstTime) {
266b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                    firstTime = false;
267b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                } else {
268b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                    sb.append(delimiter);
269b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                }
270b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                sb.append(entry.getKey().getHostAddress() + "/" +
271b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                        StructNdMsg.stringForNudState(entry.getValue()));
272b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            }
273b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            sb.append("]");
274787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
275b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        return sb.toString();
276787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    }
277787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
278787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    private boolean isWatching(InetAddress ip) {
279787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        synchronized (mLock) {
280b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            return mRunning && mIpWatchList.containsKey(ip);
281787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
282787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    }
283787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
2849ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    private boolean stillRunning() {
2859ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        synchronized (mLock) {
2869ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline            return mRunning;
2879ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        }
2889ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    }
2899ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline
290b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    private static boolean isOnLink(List<RouteInfo> routes, InetAddress ip) {
291b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        for (RouteInfo route : routes) {
292b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            if (!route.hasGateway() && route.matches(ip)) {
293b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                return true;
294b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            }
295b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        }
296b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        return false;
297b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    }
298b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline
299b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    private short getNeighborStateLocked(InetAddress ip) {
300b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        if (mIpWatchList.containsKey(ip)) {
301b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            return mIpWatchList.get(ip);
302b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        }
303b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        return StructNdMsg.NUD_NONE;
304b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    }
305b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline
306787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    public void updateLinkProperties(LinkProperties lp) {
307787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        if (!mInterfaceName.equals(lp.getInterfaceName())) {
308b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            // TODO: figure out whether / how to cope with interface changes.
309787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            Log.wtf(TAG, "requested LinkProperties interface '" + lp.getInterfaceName() +
310787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    "' does not match: " + mInterfaceName);
311787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            return;
312787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
313787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
314787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        synchronized (mLock) {
315b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            mLinkProperties = new LinkProperties(lp);
316b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            Map<InetAddress, Short> newIpWatchList = new HashMap<>();
317b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline
318b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            final List<RouteInfo> routes = mLinkProperties.getRoutes();
319b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            for (RouteInfo route : routes) {
320b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                if (route.hasGateway()) {
321b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                    InetAddress gw = route.getGateway();
322b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                    if (isOnLink(routes, gw)) {
323b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                        newIpWatchList.put(gw, getNeighborStateLocked(gw));
324b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                    }
325b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                }
326b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            }
327b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline
328b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            for (InetAddress nameserver : lp.getDnsServers()) {
329b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                if (isOnLink(routes, nameserver)) {
330b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                    newIpWatchList.put(nameserver, getNeighborStateLocked(nameserver));
331b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                }
332b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            }
333b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline
334b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            mIpWatchList = newIpWatchList;
335787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            mIpWatchListVersion++;
336787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
337787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        if (DBG) { Log.d(TAG, "watch: " + describeWatchList()); }
338787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    }
339787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
340787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    public void clearLinkProperties() {
341787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        synchronized (mLock) {
342b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            mLinkProperties.clear();
343787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            mIpWatchList.clear();
344787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            mIpWatchListVersion++;
345787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
346787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        if (DBG) { Log.d(TAG, "clear: " + describeWatchList()); }
347787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    }
348787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
349b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline    private void handleNeighborLost(String msg) {
350b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        InetAddress ip = null;
3510d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi        final ProvisioningChange delta;
352b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        synchronized (mLock) {
353b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
354b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline
355b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            for (Map.Entry<InetAddress, Short> entry : mIpWatchList.entrySet()) {
356b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                if (entry.getValue() != StructNdMsg.NUD_FAILED) {
357b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                    continue;
358b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                }
359b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline
360b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                ip = entry.getKey();
361b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                for (RouteInfo route : mLinkProperties.getRoutes()) {
362b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                    if (ip.equals(route.getGateway())) {
363b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                        whatIfLp.removeRoute(route);
364b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                    }
365b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                }
3665b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline
3675b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline                if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
3685b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline                    // We should do this unconditionally, but alas we cannot: b/31827713.
3695b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline                    whatIfLp.removeDnsServer(ip);
3705b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline                }
371b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            }
372b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline
373b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            delta = LinkProperties.compareProvisioning(mLinkProperties, whatIfLp);
374787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
375b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline
376b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline        if (delta == ProvisioningChange.LOST_PROVISIONING) {
377b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
378b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            Log.w(TAG, logMsg);
379b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            if (mCallback != null) {
380b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                // TODO: remove |ip| when the callback signature no longer has
381b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                // an InetAddress argument.
382b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                mCallback.notifyLost(ip, logMsg);
383b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            }
384787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
3850d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi        logNudFailed(delta);
386787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    }
387787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
3885b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline    private boolean avoidingBadLinks() {
3895b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline        return (mAvoidBadWifiTracker != null) ? mAvoidBadWifiTracker.currentValue() : true;
3905b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline    }
3915b437d6ff91116f25be946e07d5d90cd25c372a4Erik Kline
3929ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    public void probeAll() {
3939ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        Set<InetAddress> ipProbeList = new HashSet<InetAddress>();
3949ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        synchronized (mLock) {
395b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            ipProbeList.addAll(mIpWatchList.keySet());
3969ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        }
39776fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline
39876fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        if (!ipProbeList.isEmpty() && stillRunning()) {
39976fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline            // Keep the CPU awake long enough to allow all ARP/ND
40076fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline            // probes a reasonable chance at success. See b/23197666.
40176fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline            //
40276fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline            // The wakelock we use is (by default) refcounted, and this version
40376fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline            // of acquire(timeout) queues a release message to keep acquisitions
40476fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline            // and releases balanced.
40576fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline            mWakeLock.acquire(getProbeWakeLockDuration());
40676fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        }
40776fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline
4089ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        for (InetAddress target : ipProbeList) {
409cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline            if (!stillRunning()) {
410cef7bc939fbc3baae5ccf78dcef63fc60e07ae21Erik Kline                break;
4119ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline            }
41225bf8f5d5678e747933ae9e4051daa99ddfcfaa3Hugo Benichi            final int returnValue = probeNeighbor(mInterfaceIndex, target);
413cfddd6879283860bb4d2cf2972ea086f585a37ecHugo Benichi            logEvent(IpReachabilityEvent.PROBE, returnValue);
4149ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline        }
4150d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi        mLastProbeTimeMs = SystemClock.elapsedRealtime();
4169ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline    }
4179ce5d602cd5d732ae10efe0b648b43ddf60d65c9Erik Kline
4180d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi    private static long getProbeWakeLockDuration() {
41976fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        // Ideally, this would be computed by examining the values of:
42076fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        //
42176fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        //     /proc/sys/net/ipv[46]/neigh/<ifname>/ucast_solicit
42276fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        //
42376fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        // and:
42476fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        //
42576fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        //     /proc/sys/net/ipv[46]/neigh/<ifname>/retrans_time_ms
42676fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        //
42776fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        // For now, just make some assumptions.
42876fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        final long numUnicastProbes = 3;
42976fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        final long retransTimeMs = 1000;
43076fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        final long gracePeriodMs = 500;
43176fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline        return (numUnicastProbes * retransTimeMs) + gracePeriodMs;
43276fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline    }
43376fde62da7487d60910d3fa025dc6db5971f95d8Erik Kline
434cfddd6879283860bb4d2cf2972ea086f585a37ecHugo Benichi    private void logEvent(int probeType, int errorCode) {
4350d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi        int eventType = probeType | (errorCode & 0xff);
4360d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi        mMetricsLog.log(new IpReachabilityEvent(mInterfaceName, eventType));
4370d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi    }
4380d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi
4390d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi    private void logNudFailed(ProvisioningChange delta) {
4400d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi        long duration = SystemClock.elapsedRealtime() - mLastProbeTimeMs;
4410d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi        boolean isFromProbe = (duration < getProbeWakeLockDuration());
4420d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi        boolean isProvisioningLost = (delta == ProvisioningChange.LOST_PROVISIONING);
4430d1c65b221dee1ef80a03c25877e7fd58fc106deHugo Benichi        int eventType = IpReachabilityEvent.nudFailureEventType(isFromProbe, isProvisioningLost);
444cfddd6879283860bb4d2cf2972ea086f585a37ecHugo Benichi        mMetricsLog.log(new IpReachabilityEvent(mInterfaceName, eventType));
445cfddd6879283860bb4d2cf2972ea086f585a37ecHugo Benichi    }
446cfddd6879283860bb4d2cf2972ea086f585a37ecHugo Benichi
44755618be44c5d2a7db3cf23881cace15108f07557Pierre Imai    // TODO: simplify the number of objects by making this extend Thread.
448787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    private final class NetlinkSocketObserver implements Runnable {
449787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        private NetlinkSocket mSocket;
450787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
451787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        @Override
452787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        public void run() {
453787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            if (VDBG) { Log.d(TAG, "Starting observing thread."); }
454787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            synchronized (mLock) { mRunning = true; }
455787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
456787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            try {
457787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                setupNetlinkSocket();
458787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            } catch (ErrnoException | SocketException e) {
459787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                Log.e(TAG, "Failed to suitably initialize a netlink socket", e);
460787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                synchronized (mLock) { mRunning = false; }
461787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            }
462787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
463787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            ByteBuffer byteBuffer;
464787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            while (stillRunning()) {
465787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                try {
466787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    byteBuffer = recvKernelReply();
467787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                } catch (ErrnoException e) {
4681c01e61c90d74a8acace18466d5aa6538440cd15Erik Kline                    if (stillRunning()) { Log.w(TAG, "ErrnoException: ", e); }
469787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    break;
470787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                }
471787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                final long whenMs = SystemClock.elapsedRealtime();
472787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                if (byteBuffer == null) {
473787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    continue;
474787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                }
475787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                parseNetlinkMessageBuffer(byteBuffer, whenMs);
476787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            }
477787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
478787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            clearNetlinkSocket();
479787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
480787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            synchronized (mLock) { mRunning = false; }
481787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
482787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
483787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
484787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        private void clearNetlinkSocket() {
485787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            if (mSocket != null) {
486787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                mSocket.close();
487787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            }
488787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
489787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
490787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            // TODO: Refactor the main loop to recreate the socket upon recoverable errors.
491787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        private void setupNetlinkSocket() throws ErrnoException, SocketException {
492787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            clearNetlinkSocket();
493787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            mSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
494787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
495787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            final NetlinkSocketAddress listenAddr = new NetlinkSocketAddress(
496787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    0, OsConstants.RTMGRP_NEIGH);
497787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            mSocket.bind(listenAddr);
498787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
499787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            if (VDBG) {
500787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                final NetlinkSocketAddress nlAddr = mSocket.getLocalAddress();
501787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                Log.d(TAG, "bound to sockaddr_nl{"
502787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                        + ((long) (nlAddr.getPortId() & 0xffffffff)) + ", "
503787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                        + nlAddr.getGroupsMask()
504787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                        + "}");
505787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            }
506787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
507787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
508787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        private ByteBuffer recvKernelReply() throws ErrnoException {
509787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            try {
510787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                return mSocket.recvMessage(0);
511787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            } catch (InterruptedIOException e) {
512787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                // Interruption or other error, e.g. another thread closed our file descriptor.
513787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            } catch (ErrnoException e) {
514787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                if (e.errno != OsConstants.EAGAIN) {
515787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    throw e;
516787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                }
517787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            }
518787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            return null;
519787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
520787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
521787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) {
522787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            while (byteBuffer.remaining() > 0) {
523787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                final int position = byteBuffer.position();
524787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
525787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                if (nlMsg == null || nlMsg.getHeader() == null) {
526787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    byteBuffer.position(position);
527787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    Log.e(TAG, "unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer));
528787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    break;
529787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                }
530787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
531787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                final int srcPortId = nlMsg.getHeader().nlmsg_pid;
532787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                if (srcPortId !=  0) {
533787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    Log.e(TAG, "non-kernel source portId: " + ((long) (srcPortId & 0xffffffff)));
534787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    break;
535787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                }
536787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
537787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                if (nlMsg instanceof NetlinkErrorMessage) {
538787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    Log.e(TAG, "netlink error: " + nlMsg);
539787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    continue;
540787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) {
541787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    if (DBG) {
542787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                        Log.d(TAG, "non-rtnetlink neighbor msg: " + nlMsg);
543787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    }
544787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    continue;
545787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                }
546787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
547787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
548787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            }
549787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
550787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
551787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        private void evaluateRtNetlinkNeighborMessage(
552787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                RtNetlinkNeighborMessage neighMsg, long whenMs) {
553787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            final StructNdMsg ndMsg = neighMsg.getNdHeader();
554787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            if (ndMsg == null || ndMsg.ndm_ifindex != mInterfaceIndex) {
555787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                return;
556787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            }
557787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
558787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            final InetAddress destination = neighMsg.getDestination();
559787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            if (!isWatching(destination)) {
560787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                return;
561787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            }
562787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
563787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            final short msgType = neighMsg.getHeader().nlmsg_type;
564787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            final short nudState = ndMsg.ndm_state;
565787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            final String eventMsg = "NeighborEvent{"
566787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    + "elapsedMs=" + whenMs + ", "
567787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    + destination.getHostAddress() + ", "
568787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    + "[" + NetlinkConstants.hexify(neighMsg.getLinkLayerAddress()) + "], "
569787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    + NetlinkConstants.stringForNlMsgType(msgType) + ", "
570787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    + StructNdMsg.stringForNudState(nudState)
571787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                    + "}";
572787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
573787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            if (VDBG) {
574787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                Log.d(TAG, neighMsg.toString());
575787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            } else if (DBG) {
576787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline                Log.d(TAG, eventMsg);
577787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            }
578787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline
579b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            synchronized (mLock) {
580b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                if (mIpWatchList.containsKey(destination)) {
581b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                    final short value =
582b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                            (msgType == NetlinkConstants.RTM_DELNEIGH)
583ab06923576d4a49bc84c94badfcebcb7f6b103a8Erik Kline                            ? StructNdMsg.NUD_NONE
584b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                            : nudState;
585b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                    mIpWatchList.put(destination, value);
586b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                }
587b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline            }
588b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline
589ab06923576d4a49bc84c94badfcebcb7f6b103a8Erik Kline            if (nudState == StructNdMsg.NUD_FAILED) {
590b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                Log.w(TAG, "ALERT: " + eventMsg);
591b1eebaeb926c698eded5a892484fd9904b36cd69Erik Kline                handleNeighborLost(eventMsg);
592787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline            }
593787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline        }
594787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline    }
595787d935611c8a6d1ed66e4d718f78084fe7bd3c5Erik Kline}
596