summaryrefslogtreecommitdiff
path: root/src/android/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/net')
-rw-r--r--src/android/net/ip/IpClient.java6
-rw-r--r--src/android/net/ip/IpClientLinkObserver.java129
2 files changed, 132 insertions, 3 deletions
diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java
index 4ddcc13..3fb5001 100644
--- a/src/android/net/ip/IpClient.java
+++ b/src/android/net/ip/IpClient.java
@@ -583,7 +583,8 @@ public class IpClient extends StateMachine {
mLinkObserver = new IpClientLinkObserver(
mInterfaceName,
- () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED), config) {
+ () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED),
+ config, getHandler(), mLog) {
@Override
public void onInterfaceAdded(String iface) {
super.onInterfaceAdded(iface);
@@ -1225,6 +1226,7 @@ public class IpClient extends StateMachine {
newLp.addRoute(route);
}
addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
+ newLp.setNat64Prefix(netlinkLinkProperties.getNat64Prefix());
// [3] Add in data from DHCPv4, if available.
//
@@ -1563,6 +1565,7 @@ public class IpClient extends StateMachine {
public void enter() {
stopAllIP();
+ mLinkObserver.clearInterfaceParams();
resetLinkProperties();
if (mStartTimeMillis > 0) {
// Completed a life-cycle; send a final empty LinkProperties
@@ -1712,6 +1715,7 @@ public class IpClient extends StateMachine {
transitionTo(mStoppedState);
return;
}
+ mLinkObserver.setInterfaceParams(mInterfaceParams);
mCallback.setNeighborDiscoveryOffload(true);
}
diff --git a/src/android/net/ip/IpClientLinkObserver.java b/src/android/net/ip/IpClientLinkObserver.java
index 02bf5f0..bbd2176 100644
--- a/src/android/net/ip/IpClientLinkObserver.java
+++ b/src/android/net/ip/IpClientLinkObserver.java
@@ -16,12 +16,27 @@
package android.net.ip;
+import static android.system.OsConstants.AF_INET6;
+
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
+
import android.net.InetAddresses;
+import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
+import android.net.netlink.NduseroptMessage;
+import android.net.netlink.NetlinkConstants;
+import android.net.netlink.NetlinkMessage;
+import android.net.netlink.StructNdOptPref64;
+import android.net.util.InterfaceParams;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.system.OsConstants;
import android.util.Log;
+import com.android.networkstack.apishim.NetworkInformationShim;
+import com.android.networkstack.apishim.NetworkInformationShimImpl;
import com.android.server.NetworkObserver;
import java.net.InetAddress;
@@ -31,6 +46,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
/**
* Keeps track of link configuration received from Netd.
@@ -56,6 +72,10 @@ import java.util.Set;
* - All accesses to mLinkProperties must be synchronized(this). All the other
* member variables are immutable once the object is constructed.
*
+ * TODO: Now that all the methods are called on the handler thread, remove synchronization and
+ * pass the LinkProperties to the update() callback.
+ * TODO: Stop extending NetworkObserver and get events from netlink directly.
+ *
* @hide
*/
public class IpClientLinkObserver implements NetworkObserver {
@@ -86,16 +106,21 @@ public class IpClientLinkObserver implements NetworkObserver {
private DnsServerRepository mDnsServerRepository;
private final Configuration mConfig;
+ private final MyNetlinkMonitor mNetlinkMonitor;
+
private static final boolean DBG = false;
- public IpClientLinkObserver(String iface, Callback callback, Configuration config) {
- mTag = "NetlinkTracker/" + iface;
+ public IpClientLinkObserver(String iface, Callback callback, Configuration config,
+ Handler h, SharedLog log) {
mInterfaceName = iface;
+ mTag = "NetlinkTracker/" + mInterfaceName;
mCallback = callback;
mLinkProperties = new LinkProperties();
mLinkProperties.setInterfaceName(mInterfaceName);
mConfig = config;
mDnsServerRepository = new DnsServerRepository(config.minRdnssLifetime);
+ mNetlinkMonitor = new MyNetlinkMonitor(h, log, mTag);
+ h.post(mNetlinkMonitor::start);
}
private void maybeLog(String operation, String iface, LinkAddress address) {
@@ -213,6 +238,106 @@ public class IpClientLinkObserver implements NetworkObserver {
mLinkProperties.setInterfaceName(mInterfaceName);
}
+ /** Notifies this object of new interface parameters. */
+ public void setInterfaceParams(InterfaceParams params) {
+ mNetlinkMonitor.setIfindex(params.index);
+ }
+
+ /** Notifies this object not to listen on any interface. */
+ public void clearInterfaceParams() {
+ mNetlinkMonitor.setIfindex(0); // 0 is never a valid ifindex.
+ }
+
+ /**
+ * Simple NetlinkMonitor. Currently only listens for PREF64 events.
+ * All methods except the constructor must be called on the handler thread.
+ */
+ private class MyNetlinkMonitor extends NetlinkMonitor {
+ MyNetlinkMonitor(Handler h, SharedLog log, String tag) {
+ super(h, log, tag, OsConstants.NETLINK_ROUTE, NetlinkConstants.RTMGRP_ND_USEROPT);
+ }
+
+ private final NetworkInformationShim mShim = NetworkInformationShimImpl.newInstance();
+
+ private long mNat64PrefixExpiry;
+
+ /**
+ * Current interface index. Most of this class (and of IpClient), only uses interface names,
+ * not interface indices. This means that the interface index can in theory change, and that
+ * it's not necessarily correct to get the interface name at object creation time (and in
+ * fact, when the object is created, the interface might not even exist).
+ * TODO: once all netlink events pass through this class, stop depending on interface names.
+ */
+ private int mIfindex;
+
+ void setIfindex(int ifindex) {
+ mIfindex = ifindex;
+ }
+
+ /**
+ * Processes a PREF64 ND option.
+ *
+ * @param prefix The NAT64 prefix.
+ * @param now The time (as determined by SystemClock.elapsedRealtime) when the event
+ * that triggered this method was received.
+ * @param expiry The time (as determined by SystemClock.elapsedRealtime) when the option
+ * expires.
+ */
+ private synchronized void updatePref64(IpPrefix prefix, final long now,
+ final long expiry) {
+ final IpPrefix currentPrefix = mShim.getNat64Prefix(mLinkProperties);
+
+ // If the prefix matches the current prefix, refresh its lifetime.
+ if (prefix.equals(currentPrefix)) {
+ mNat64PrefixExpiry = expiry;
+ }
+
+ // If we already have a prefix, continue using it and ignore the new one. Stopping and
+ // restarting clatd is disruptive because it will break existing IPv4 connections.
+ if (mNat64PrefixExpiry > now) return;
+
+ // The current prefix has expired. Either replace it with the new one or delete it.
+ if (expiry > now) {
+ // If expiry > now, then prefix != currentPrefix (due to the return statement above)
+ mShim.setNat64Prefix(mLinkProperties, prefix);
+ mNat64PrefixExpiry = expiry;
+ } else {
+ mShim.setNat64Prefix(mLinkProperties, null);
+ mNat64PrefixExpiry = 0;
+ }
+
+ mCallback.update();
+
+ // TODO: send a delayed message to remove the prefix when it expires.
+ }
+
+ private void processPref64Option(StructNdOptPref64 opt, final long now) {
+ final long expiry = now + TimeUnit.SECONDS.toMillis(opt.lifetime);
+ updatePref64(opt.prefix, now, expiry);
+ }
+
+ private void processNduseroptMessage(NduseroptMessage msg, final long whenMs) {
+ if (msg.family != AF_INET6 || msg.option == null || msg.ifindex != mIfindex) return;
+ if (msg.icmp_type != (byte) ICMPV6_ROUTER_ADVERTISEMENT) return;
+
+ switch (msg.option.type) {
+ case StructNdOptPref64.TYPE:
+ processPref64Option((StructNdOptPref64) msg.option, whenMs);
+ break;
+
+ default:
+ // TODO: implement RDNSS and DNSSL.
+ break;
+ }
+ }
+
+ @Override
+ protected void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) {
+ if (!(nlMsg instanceof NduseroptMessage)) return;
+ processNduseroptMessage((NduseroptMessage) nlMsg, whenMs);
+ }
+ }
+
/**
* Tracks DNS server updates received from Netlink.
*