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