diff options
| author | 2018-01-11 04:02:15 +0000 | |
|---|---|---|
| committer | 2018-01-11 04:02:15 +0000 | |
| commit | 2be133a54e20494f1bce199e57f6f48b9e693a04 (patch) | |
| tree | 516771f86ff65aa1d53cacb6879a5207a07073be | |
| parent | 360d2cb49442a973c6db87743575be22ef7b6cc5 (diff) | |
| parent | fe83298cd5de0d7228883890711d15debd18dcbf (diff) | |
Merge "Refactor to InterfaceParams utility class" am: 6a91687bcd
am: fe83298cd5
Change-Id: Icb708a5ea7c3b41cb9d23885018b088c65ee427b
14 files changed, 275 insertions, 169 deletions
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java index 17adb1a74e30..2224913b2cf6 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java @@ -30,6 +30,7 @@ import android.net.RouteInfo; import android.net.ip.InterfaceController; import android.net.ip.RouterAdvertisementDaemon; import android.net.ip.RouterAdvertisementDaemon.RaParams; +import android.net.util.InterfaceParams; import android.net.util.NetdService; import android.net.util.SharedLog; import android.os.INetworkManagementService; @@ -48,7 +49,6 @@ import com.android.internal.util.StateMachine; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; @@ -120,8 +120,7 @@ public class TetherInterfaceStateMachine extends StateMachine { private int mLastError; private int mServingMode; private String mMyUpstreamIfaceName; // may change over time - private NetworkInterface mNetworkInterface; - private byte[] mHwAddr; + private InterfaceParams mInterfaceParams; // TODO: De-duplicate this with mLinkProperties above. Currently, these link // properties are those selected by the IPv6TetheringCoordinator and relayed // to us. By comparison, mLinkProperties contains the addresses and directly @@ -247,31 +246,16 @@ public class TetherInterfaceStateMachine extends StateMachine { } private boolean startIPv6() { - // TODO: Refactor for testability (perhaps passing an android.system.Os - // instance and calling getifaddrs() directly). - try { - mNetworkInterface = NetworkInterface.getByName(mIfaceName); - } catch (SocketException e) { - mLog.e("Error looking up NetworkInterfaces: " + e); - stopIPv6(); - return false; - } - if (mNetworkInterface == null) { - mLog.e("Failed to find NetworkInterface"); - stopIPv6(); - return false; - } - - try { - mHwAddr = mNetworkInterface.getHardwareAddress(); - } catch (SocketException e) { - mLog.e("Failed to find hardware address: " + e); + // TODO: Refactor for better testability. This is one of the things + // that prohibits unittesting IPv6 tethering setup. + mInterfaceParams = InterfaceParams.getByName(mIfaceName); + if (mInterfaceParams == null) { + mLog.e("Failed to find InterfaceParams"); stopIPv6(); return false; } - final int ifindex = mNetworkInterface.getIndex(); - mRaDaemon = new RouterAdvertisementDaemon(mIfaceName, ifindex, mHwAddr); + mRaDaemon = new RouterAdvertisementDaemon(mInterfaceParams); if (!mRaDaemon.start()) { stopIPv6(); return false; @@ -281,8 +265,7 @@ public class TetherInterfaceStateMachine extends StateMachine { } private void stopIPv6() { - mNetworkInterface = null; - mHwAddr = null; + mInterfaceParams = null; setRaParams(null); if (mRaDaemon != null) { diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index 31a1abb39461..7d9736ed3fe5 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -38,6 +38,7 @@ import android.net.metrics.ApfProgramEvent; import android.net.metrics.ApfStats; import android.net.metrics.IpConnectivityLog; import android.net.metrics.RaEvent; +import android.net.util.InterfaceParams; import android.system.ErrnoException; import android.system.Os; import android.system.PacketSocketAddress; @@ -56,7 +57,6 @@ import java.lang.Thread; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.nio.ByteBuffer; @@ -247,7 +247,7 @@ public class ApfFilter { private final ApfCapabilities mApfCapabilities; private final IpClient.Callback mIpClientCallback; - private final NetworkInterface mNetworkInterface; + private final InterfaceParams mInterfaceParams; private final IpConnectivityLog mMetricsLog; @VisibleForTesting @@ -269,11 +269,11 @@ public class ApfFilter { private int mIPv4PrefixLength; @VisibleForTesting - ApfFilter(ApfConfiguration config, NetworkInterface networkInterface, + ApfFilter(ApfConfiguration config, InterfaceParams ifParams, IpClient.Callback ipClientCallback, IpConnectivityLog log) { mApfCapabilities = config.apfCapabilities; mIpClientCallback = ipClientCallback; - mNetworkInterface = networkInterface; + mInterfaceParams = ifParams; mMulticastFilter = config.multicastFilter; mDrop802_3Frames = config.ieee802_3Filter; @@ -287,7 +287,7 @@ public class ApfFilter { } private void log(String s) { - Log.d(TAG, "(" + mNetworkInterface.getName() + "): " + s); + Log.d(TAG, "(" + mInterfaceParams.name + "): " + s); } @GuardedBy("this") @@ -332,14 +332,14 @@ public class ApfFilter { void maybeStartFilter() { FileDescriptor socket; try { - mHardwareAddress = mNetworkInterface.getHardwareAddress(); + mHardwareAddress = mInterfaceParams.macAddr.toByteArray(); synchronized(this) { // Install basic filters installNewProgramLocked(); } socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6); - PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, - mNetworkInterface.getIndex()); + PacketSocketAddress addr = new PacketSocketAddress( + (short) ETH_P_IPV6, mInterfaceParams.index); Os.bind(socket, addr); NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat); } catch(SocketException|ErrnoException e) { @@ -1168,10 +1168,10 @@ public class ApfFilter { * filtering using APF programs. */ public static ApfFilter maybeCreate(ApfConfiguration config, - NetworkInterface networkInterface, IpClient.Callback ipClientCallback) { - if (config == null) return null; + InterfaceParams ifParams, IpClient.Callback ipClientCallback) { + if (config == null || ifParams == null) return null; ApfCapabilities apfCapabilities = config.apfCapabilities; - if (apfCapabilities == null || networkInterface == null) return null; + if (apfCapabilities == null) return null; if (apfCapabilities.apfVersionSupported == 0) return null; if (apfCapabilities.maximumApfProgramSize < 512) { Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize); @@ -1186,7 +1186,7 @@ public class ApfFilter { Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported); return null; } - return new ApfFilter(config, networkInterface, ipClientCallback, new IpConnectivityLog()); + return new ApfFilter(config, ifParams, ipClientCallback, new IpConnectivityLog()); } public synchronized void shutdown() { diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java index ed78175bd395..9056312da681 100644 --- a/services/net/java/android/net/dhcp/DhcpClient.java +++ b/services/net/java/android/net/dhcp/DhcpClient.java @@ -34,6 +34,7 @@ import android.net.TrafficStats; import android.net.metrics.IpConnectivityLog; import android.net.metrics.DhcpClientEvent; import android.net.metrics.DhcpErrorEvent; +import android.net.util.InterfaceParams; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; @@ -50,7 +51,6 @@ import java.io.FileDescriptor; import java.io.IOException; import java.lang.Thread; import java.net.Inet4Address; -import java.net.NetworkInterface; import java.net.SocketException; import java.nio.ByteBuffer; import java.util.Arrays; @@ -187,7 +187,8 @@ public class DhcpClient extends StateMachine { private final String mIfaceName; private boolean mRegisteredForPreDhcpNotification; - private NetworkInterface mIface; + private InterfaceParams mIface; + // TODO: MacAddress-ify more of this class hierarchy. private byte[] mHwAddr; private PacketSocketAddress mInterfaceBroadcastAddr; private int mTransactionId; @@ -221,6 +222,7 @@ public class DhcpClient extends StateMachine { return new WakeupMessage(mContext, getHandler(), cmdName, cmd); } + // TODO: Take an InterfaceParams instance instead of an interface name String. private DhcpClient(Context context, StateMachine controller, String iface) { super(TAG); @@ -262,23 +264,23 @@ public class DhcpClient extends StateMachine { } public static DhcpClient makeDhcpClient( - Context context, StateMachine controller, String intf) { - DhcpClient client = new DhcpClient(context, controller, intf); + Context context, StateMachine controller, InterfaceParams ifParams) { + DhcpClient client = new DhcpClient(context, controller, ifParams.name); + client.mIface = ifParams; client.start(); return client; } private boolean initInterface() { - try { - mIface = NetworkInterface.getByName(mIfaceName); - mHwAddr = mIface.getHardwareAddress(); - mInterfaceBroadcastAddr = new PacketSocketAddress(mIface.getIndex(), - DhcpPacket.ETHER_BROADCAST); - return true; - } catch(SocketException | NullPointerException e) { - Log.e(TAG, "Can't determine ifindex or MAC address for " + mIfaceName, e); + if (mIface == null) mIface = InterfaceParams.getByName(mIfaceName); + if (mIface == null) { + Log.e(TAG, "Can't determine InterfaceParams for " + mIfaceName); return false; } + + mHwAddr = mIface.macAddr.toByteArray(); + mInterfaceBroadcastAddr = new PacketSocketAddress(mIface.index, DhcpPacket.ETHER_BROADCAST); + return true; } private void startNewTransaction() { @@ -293,7 +295,7 @@ public class DhcpClient extends StateMachine { private boolean initPacketSocket() { try { mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP); - PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.getIndex()); + PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.index); Os.bind(mPacketSock, addr); NetworkUtils.attachDhcpFilter(mPacketSock); } catch(SocketException|ErrnoException e) { diff --git a/services/net/java/android/net/ip/ConnectivityPacketTracker.java b/services/net/java/android/net/ip/ConnectivityPacketTracker.java index 6cf4fa9a3dfc..e6ddbbc95469 100644 --- a/services/net/java/android/net/ip/ConnectivityPacketTracker.java +++ b/services/net/java/android/net/ip/ConnectivityPacketTracker.java @@ -21,6 +21,7 @@ import static android.system.OsConstants.*; import android.net.NetworkUtils; import android.net.util.PacketReader; import android.net.util.ConnectivityPacketSummary; +import android.net.util.InterfaceParams; import android.os.Handler; import android.system.ErrnoException; import android.system.Os; @@ -35,7 +36,6 @@ import libcore.util.HexEncoding; import java.io.FileDescriptor; import java.io.InterruptedIOException; import java.io.IOException; -import java.net.NetworkInterface; import java.net.SocketException; @@ -69,24 +69,12 @@ public class ConnectivityPacketTracker { private boolean mRunning; private String mDisplayName; - public ConnectivityPacketTracker(Handler h, NetworkInterface netif, LocalLog log) { - final String ifname; - final int ifindex; - final byte[] hwaddr; - final int mtu; - - try { - ifname = netif.getName(); - ifindex = netif.getIndex(); - hwaddr = netif.getHardwareAddress(); - mtu = netif.getMTU(); - } catch (NullPointerException|SocketException e) { - throw new IllegalArgumentException("bad network interface", e); - } + public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) { + if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams"); - mTag = TAG + "." + ifname; + mTag = TAG + "." + ifParams.name; mLog = log; - mPacketListener = new PacketListener(h, ifindex, hwaddr, mtu); + mPacketListener = new PacketListener(h, ifParams); } public void start(String displayName) { @@ -102,13 +90,11 @@ public class ConnectivityPacketTracker { } private final class PacketListener extends PacketReader { - private final int mIfIndex; - private final byte mHwAddr[]; + private final InterfaceParams mInterface; - PacketListener(Handler h, int ifindex, byte[] hwaddr, int mtu) { - super(h, mtu); - mIfIndex = ifindex; - mHwAddr = hwaddr; + PacketListener(Handler h, InterfaceParams ifParams) { + super(h, ifParams.defaultMtu); + mInterface = ifParams; } @Override @@ -117,7 +103,7 @@ public class ConnectivityPacketTracker { try { s = Os.socket(AF_PACKET, SOCK_RAW, 0); NetworkUtils.attachControlPacketFilter(s, ARPHRD_ETHER); - Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mIfIndex)); + Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mInterface.index)); } catch (ErrnoException | IOException e) { logError("Failed to create packet tracking socket: ", e); closeFd(s); @@ -129,7 +115,7 @@ public class ConnectivityPacketTracker { @Override protected void handlePacket(byte[] recvbuf, int length) { final String summary = ConnectivityPacketSummary.summarize( - mHwAddr, recvbuf, length); + mInterface.macAddr, recvbuf, length); if (summary == null) return; if (DBG) Log.d(mTag, summary); diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java index fdb366c55a7b..d3a97b3851f4 100644 --- a/services/net/java/android/net/ip/IpClient.java +++ b/services/net/java/android/net/ip/IpClient.java @@ -35,6 +35,7 @@ import android.net.apf.ApfFilter; import android.net.dhcp.DhcpClient; import android.net.metrics.IpConnectivityLog; import android.net.metrics.IpManagerEvent; +import android.net.util.InterfaceParams; import android.net.util.MultinetworkPolicyTracker; import android.net.util.NetdService; import android.net.util.NetworkConstants; @@ -63,7 +64,6 @@ import java.io.PrintWriter; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.NetworkInterface; import java.net.SocketException; import java.util.ArrayList; import java.util.Collection; @@ -556,7 +556,7 @@ public class IpClient extends StateMachine { private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); private final InterfaceController mInterfaceCtrl; - private NetworkInterface mNetworkInterface; + private InterfaceParams mInterfaceParams; /** * Non-final member variables accessed only from within our StateMachine. @@ -722,7 +722,12 @@ public class IpClient extends StateMachine { return; } - getNetworkInterface(); + mInterfaceParams = InterfaceParams.getByName(mInterfaceName); + if (mInterfaceParams == null) { + logError("Failed to find InterfaceParams for " + mInterfaceName); + // TODO: call doImmediateProvisioningFailure() with an error code + // indicating something like "interface not ready". + } mCallback.setNeighborDiscoveryOffload(true); sendMessage(CMD_START, new ProvisioningConfiguration(req)); @@ -858,7 +863,7 @@ public class IpClient extends StateMachine { protected String getLogRecString(Message msg) { final String logLine = String.format( "%s/%d %d %d %s [%s]", - mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(), + mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index, msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger); final String richerLogLine = getWhatToString(msg.what) + " " + logLine; @@ -889,15 +894,6 @@ public class IpClient extends StateMachine { mLog.log(msg); } - private void getNetworkInterface() { - try { - mNetworkInterface = NetworkInterface.getByName(mInterfaceName); - } catch (SocketException | NullPointerException e) { - // TODO: throw new IllegalStateException. - logError("Failed to get interface object: %s", e); - } - } - // This needs to be called with care to ensure that our LinkProperties // are in sync with the actual LinkProperties of the interface. For example, // we should only call this if we know for sure that there are no IP addresses @@ -1218,7 +1214,7 @@ public class IpClient extends StateMachine { } } else { // Start DHCPv4. - mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceName); + mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams); mDhcpClient.registerForPreDhcpNotification(); mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP); } @@ -1245,7 +1241,7 @@ public class IpClient extends StateMachine { try { mIpReachabilityMonitor = new IpReachabilityMonitor( mContext, - mInterfaceName, + mInterfaceParams, getHandler(), mLog, new IpReachabilityMonitor.Callback() { @@ -1447,7 +1443,7 @@ public class IpClient extends StateMachine { mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames); apfConfig.ethTypeBlackList = mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList); - mApfFilter = ApfFilter.maybeCreate(apfConfig, mNetworkInterface, mCallback); + mApfFilter = ApfFilter.maybeCreate(apfConfig, mInterfaceParams, mCallback); // TODO: investigate the effects of any multicast filtering racing/interfering with the // rest of this IP configuration startup. if (mApfFilter == null) { @@ -1515,7 +1511,7 @@ public class IpClient extends StateMachine { private ConnectivityPacketTracker createPacketTracker() { try { return new ConnectivityPacketTracker( - getHandler(), mNetworkInterface, mConnectivityPacketLog); + getHandler(), mInterfaceParams, mConnectivityPacketLog); } catch (IllegalArgumentException e) { return null; } diff --git a/services/net/java/android/net/ip/IpNeighborMonitor.java b/services/net/java/android/net/ip/IpNeighborMonitor.java index 680733478657..fc07aa1ecd17 100644 --- a/services/net/java/android/net/ip/IpNeighborMonitor.java +++ b/services/net/java/android/net/ip/IpNeighborMonitor.java @@ -16,7 +16,11 @@ package android.net.ip; -import android.net.netlink.NetlinkConstants; +import static android.net.netlink.NetlinkConstants.hexify; +import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH; +import static android.net.netlink.NetlinkConstants.stringForNlMsgType; + +import android.net.MacAddress; import android.net.netlink.NetlinkErrorMessage; import android.net.netlink.NetlinkMessage; import android.net.netlink.NetlinkSocket; @@ -92,37 +96,35 @@ public class IpNeighborMonitor extends PacketReader { final int ifindex; final InetAddress ip; final short nudState; - final byte[] linkLayerAddr; + final MacAddress macAddr; public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip, - short nudState, byte[] linkLayerAddr) { + short nudState, MacAddress macAddr) { this.elapsedMs = elapsedMs; this.msgType = msgType; this.ifindex = ifindex; this.ip = ip; this.nudState = nudState; - this.linkLayerAddr = linkLayerAddr; + this.macAddr = macAddr; } boolean isConnected() { - return (msgType != NetlinkConstants.RTM_DELNEIGH) && - StructNdMsg.isNudStateConnected(nudState); + return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState); } boolean isValid() { - return (msgType != NetlinkConstants.RTM_DELNEIGH) && - StructNdMsg.isNudStateValid(nudState); + return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState); } @Override public String toString() { final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}"); return j.add("@" + elapsedMs) - .add(NetlinkConstants.stringForNlMsgType(msgType)) + .add(stringForNlMsgType(msgType)) .add("if=" + ifindex) .add(ip.getHostAddress()) .add(StructNdMsg.stringForNudState(nudState)) - .add("[" + NetlinkConstants.hexify(linkLayerAddr) + "]") + .add("[" + macAddr + "]") .toString(); } } @@ -183,7 +185,7 @@ public class IpNeighborMonitor extends PacketReader { final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer); if (nlMsg == null || nlMsg.getHeader() == null) { byteBuffer.position(position); - mLog.e("unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer)); + mLog.e("unparsable netlink msg: " + hexify(byteBuffer)); break; } @@ -217,12 +219,13 @@ public class IpNeighborMonitor extends PacketReader { final int ifindex = ndMsg.ndm_ifindex; final InetAddress destination = neighMsg.getDestination(); final short nudState = - (msgType == NetlinkConstants.RTM_DELNEIGH) + (msgType == RTM_DELNEIGH) ? StructNdMsg.NUD_NONE : ndMsg.ndm_state; final NeighborEvent event = new NeighborEvent( - whenMs, msgType, ifindex, destination, nudState, neighMsg.getLinkLayerAddress()); + whenMs, msgType, ifindex, destination, nudState, + getMacAddress(neighMsg.getLinkLayerAddress())); if (VDBG) { Log.d(TAG, neighMsg.toString()); @@ -233,4 +236,16 @@ public class IpNeighborMonitor extends PacketReader { mConsumer.accept(event); } + + private static MacAddress getMacAddress(byte[] linkLayerAddress) { + if (linkLayerAddress != null) { + try { + return MacAddress.fromBytes(linkLayerAddress); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed to parse link-layer address: " + hexify(linkLayerAddress)); + } + } + + return null; + } } diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java index b31ffbba0279..7e02a2881da8 100644 --- a/services/net/java/android/net/ip/IpReachabilityMonitor.java +++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java @@ -26,6 +26,7 @@ import android.net.ip.IpNeighborMonitor.NeighborEvent; import android.net.metrics.IpConnectivityLog; import android.net.metrics.IpReachabilityEvent; import android.net.netlink.StructNdMsg; +import android.net.util.InterfaceParams; import android.net.util.MultinetworkPolicyTracker; import android.net.util.SharedLog; import android.os.Handler; @@ -46,9 +47,7 @@ import java.io.PrintWriter; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.NetworkInterface; import java.net.SocketAddress; -import java.net.SocketException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; @@ -168,8 +167,7 @@ public class IpReachabilityMonitor { } } - private final String mInterfaceName; - private final int mInterfaceIndex; + private final InterfaceParams mInterfaceParams; private final IpNeighborMonitor mIpNeighborMonitor; private final SharedLog mLog; private final Callback mCallback; @@ -182,30 +180,25 @@ public class IpReachabilityMonitor { private volatile long mLastProbeTimeMs; public IpReachabilityMonitor( - Context context, String ifName, Handler h, SharedLog log, Callback callback) { - this(context, ifName, h, log, callback, null); - } - - public IpReachabilityMonitor( - Context context, String ifName, Handler h, SharedLog log, Callback callback, + Context context, InterfaceParams ifParams, Handler h, SharedLog log, Callback callback, MultinetworkPolicyTracker tracker) { - this(ifName, getInterfaceIndex(ifName), h, log, callback, tracker, - Dependencies.makeDefault(context, ifName)); + this(ifParams, h, log, callback, tracker, Dependencies.makeDefault(context, ifParams.name)); } @VisibleForTesting - IpReachabilityMonitor(String ifName, int ifIndex, Handler h, SharedLog log, Callback callback, + IpReachabilityMonitor(InterfaceParams ifParams, Handler h, SharedLog log, Callback callback, MultinetworkPolicyTracker tracker, Dependencies dependencies) { - mInterfaceName = ifName; + if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams"); + + mInterfaceParams = ifParams; mLog = log.forSubComponent(TAG); mCallback = callback; mMultinetworkPolicyTracker = tracker; - mInterfaceIndex = ifIndex; mDependencies = dependencies; mIpNeighborMonitor = new IpNeighborMonitor(h, mLog, (NeighborEvent event) -> { - if (mInterfaceIndex != event.ifindex) return; + if (mInterfaceParams.index != event.ifindex) return; if (!mNeighborWatchList.containsKey(event.ip)) return; final NeighborEvent prev = mNeighborWatchList.put(event.ip, event); @@ -241,7 +234,7 @@ public class IpReachabilityMonitor { private String describeWatchList(String sep) { final StringBuilder sb = new StringBuilder(); - sb.append("iface{" + mInterfaceName + "/" + mInterfaceIndex + "}," + sep); + sb.append("iface{" + mInterfaceParams + "}," + sep); sb.append("ntable=[" + sep); String delimiter = ""; for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) { @@ -262,10 +255,10 @@ public class IpReachabilityMonitor { } public void updateLinkProperties(LinkProperties lp) { - if (!mInterfaceName.equals(lp.getInterfaceName())) { + if (!mInterfaceParams.name.equals(lp.getInterfaceName())) { // TODO: figure out whether / how to cope with interface changes. Log.wtf(TAG, "requested LinkProperties interface '" + lp.getInterfaceName() + - "' does not match: " + mInterfaceName); + "' does not match: " + mInterfaceParams.name); return; } @@ -353,10 +346,10 @@ public class IpReachabilityMonitor { mDependencies.acquireWakeLock(getProbeWakeLockDuration()); } - for (InetAddress target : ipProbeList) { - final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceIndex, target); + for (InetAddress ip : ipProbeList) { + final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceParams.index, ip); mLog.log(String.format("put neighbor %s into NUD_PROBE state (rval=%d)", - target.getHostAddress(), rval)); + ip.getHostAddress(), rval)); logEvent(IpReachabilityEvent.PROBE, rval); } mLastProbeTimeMs = SystemClock.elapsedRealtime(); @@ -378,22 +371,9 @@ public class IpReachabilityMonitor { return (numUnicastProbes * retransTimeMs) + gracePeriodMs; } - private static int getInterfaceIndex(String ifname) { - final NetworkInterface iface; - try { - iface = NetworkInterface.getByName(ifname); - } catch (SocketException e) { - throw new IllegalArgumentException("invalid interface '" + ifname + "': ", e); - } - if (iface == null) { - throw new IllegalArgumentException("NetworkInterface was null for " + ifname); - } - return iface.getIndex(); - } - private void logEvent(int probeType, int errorCode) { int eventType = probeType | (errorCode & 0xff); - mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType)); + mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType)); } private void logNudFailed(ProvisioningChange delta) { @@ -401,6 +381,6 @@ public class IpReachabilityMonitor { boolean isFromProbe = (duration < getProbeWakeLockDuration()); boolean isProvisioningLost = (delta == ProvisioningChange.LOST_PROVISIONING); int eventType = IpReachabilityEvent.nudFailureEventType(isFromProbe, isProvisioningLost); - mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType)); + mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType)); } } diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java index cb3123ce466a..49a1e79fd71e 100644 --- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java +++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java @@ -25,6 +25,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkUtils; import android.net.TrafficStats; +import android.net.util.InterfaceParams; import android.system.ErrnoException; import android.system.Os; import android.system.StructGroupReq; @@ -96,9 +97,7 @@ public class RouterAdvertisementDaemon { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - private final String mIfName; - private final int mIfIndex; - private final byte[] mHwAddr; + private final InterfaceParams mInterface; private final InetSocketAddress mAllNodes; // This lock is to protect the RA from being updated while being @@ -223,11 +222,9 @@ public class RouterAdvertisementDaemon { } - public RouterAdvertisementDaemon(String ifname, int ifindex, byte[] hwaddr) { - mIfName = ifname; - mIfIndex = ifindex; - mHwAddr = hwaddr; - mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mIfIndex), 0); + public RouterAdvertisementDaemon(InterfaceParams ifParams) { + mInterface = ifParams; + mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0); mDeprecatedInfoTracker = new DeprecatedInfoTracker(); } @@ -279,7 +276,7 @@ public class RouterAdvertisementDaemon { try { putHeader(ra, mRaParams != null && mRaParams.hasDefaultRoute); - putSlla(ra, mHwAddr); + putSlla(ra, mInterface.macAddr.toByteArray()); mRaLength = ra.position(); // https://tools.ietf.org/html/rfc5175#section-4 says: @@ -579,9 +576,9 @@ public class RouterAdvertisementDaemon { // Setting SNDTIMEO is purely for defensive purposes. Os.setsockoptTimeval( mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(SEND_TIMEOUT_MS)); - Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mIfName); + Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mInterface.name); NetworkUtils.protectFromVpn(mSocket); - NetworkUtils.setupRaSocket(mSocket, mIfIndex); + NetworkUtils.setupRaSocket(mSocket, mInterface.index); } catch (ErrnoException | IOException e) { Log.e(TAG, "Failed to create RA daemon socket: " + e); return false; @@ -614,7 +611,7 @@ public class RouterAdvertisementDaemon { final InetAddress destip = dest.getAddress(); return (destip instanceof Inet6Address) && destip.isLinkLocalAddress() && - (((Inet6Address) destip).getScopeId() == mIfIndex); + (((Inet6Address) destip).getScopeId() == mInterface.index); } private void maybeSendRA(InetSocketAddress dest) { diff --git a/services/net/java/android/net/util/ConnectivityPacketSummary.java b/services/net/java/android/net/util/ConnectivityPacketSummary.java index dae93afb6599..4951400eed84 100644 --- a/services/net/java/android/net/util/ConnectivityPacketSummary.java +++ b/services/net/java/android/net/util/ConnectivityPacketSummary.java @@ -17,6 +17,7 @@ package android.net.util; import android.net.dhcp.DhcpPacket; +import android.net.MacAddress; import java.net.InetAddress; import java.net.UnknownHostException; @@ -45,21 +46,20 @@ public class ConnectivityPacketSummary { private final ByteBuffer mPacket; private final String mSummary; - public static String summarize(byte[] hwaddr, byte[] buffer) { + public static String summarize(MacAddress hwaddr, byte[] buffer) { return summarize(hwaddr, buffer, buffer.length); } // Methods called herein perform some but by no means all error checking. // They may throw runtime exceptions on malformed packets. - public static String summarize(byte[] hwaddr, byte[] buffer, int length) { - if ((hwaddr == null) || (hwaddr.length != ETHER_ADDR_LEN)) return null; - if (buffer == null) return null; + public static String summarize(MacAddress macAddr, byte[] buffer, int length) { + if ((macAddr == null) || (buffer == null)) return null; length = Math.min(length, buffer.length); - return (new ConnectivityPacketSummary(hwaddr, buffer, length)).toString(); + return (new ConnectivityPacketSummary(macAddr, buffer, length)).toString(); } - private ConnectivityPacketSummary(byte[] hwaddr, byte[] buffer, int length) { - mHwAddr = hwaddr; + private ConnectivityPacketSummary(MacAddress macAddr, byte[] buffer, int length) { + mHwAddr = macAddr.toByteArray(); mBytes = buffer; mLength = Math.min(length, mBytes.length); mPacket = ByteBuffer.wrap(mBytes, 0, mLength); diff --git a/services/net/java/android/net/util/InterfaceParams.java b/services/net/java/android/net/util/InterfaceParams.java new file mode 100644 index 000000000000..a4b2fbb6d963 --- /dev/null +++ b/services/net/java/android/net/util/InterfaceParams.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.util; + +import static android.net.MacAddress.ALL_ZEROS_ADDRESS; +import static android.net.util.NetworkConstants.ETHER_MTU; +import static android.net.util.NetworkConstants.IPV6_MIN_MTU; +import static com.android.internal.util.Preconditions.checkArgument; + +import android.net.MacAddress; +import android.text.TextUtils; + +import java.net.NetworkInterface; +import java.net.SocketException; + + +/** + * Encapsulate the interface parameters common to IpClient/IpServer components. + * + * Basically all java.net.NetworkInterface methods throw Exceptions. IpClient + * and IpServer (sub)components need most or all of this information at some + * point during their lifecycles, so pass only this simplified object around + * which can be created once when IpClient/IpServer are told to start. + * + * @hide + */ +public class InterfaceParams { + public final String name; + public final int index; + public final MacAddress macAddr; + public final int defaultMtu; + + public static InterfaceParams getByName(String name) { + final NetworkInterface netif = getNetworkInterfaceByName(name); + if (netif == null) return null; + + // Not all interfaces have MAC addresses, e.g. rmnet_data0. + final MacAddress macAddr = getMacAddress(netif); + + try { + return new InterfaceParams(name, netif.getIndex(), macAddr, netif.getMTU()); + } catch (IllegalArgumentException|SocketException e) { + return null; + } + } + + public InterfaceParams(String name, int index, MacAddress macAddr) { + this(name, index, macAddr, ETHER_MTU); + } + + public InterfaceParams(String name, int index, MacAddress macAddr, int defaultMtu) { + checkArgument((!TextUtils.isEmpty(name)), "impossible interface name"); + checkArgument((index > 0), "invalid interface index"); + this.name = name; + this.index = index; + this.macAddr = (macAddr != null) ? macAddr : ALL_ZEROS_ADDRESS; + this.defaultMtu = (defaultMtu > IPV6_MIN_MTU) ? defaultMtu : IPV6_MIN_MTU; + } + + @Override + public String toString() { + return String.format("%s/%d/%s/%d", name, index, macAddr, defaultMtu); + } + + private static NetworkInterface getNetworkInterfaceByName(String name) { + try { + return NetworkInterface.getByName(name); + } catch (NullPointerException|SocketException e) { + return null; + } + } + + private static MacAddress getMacAddress(NetworkInterface netif) { + try { + return MacAddress.fromBytes(netif.getHardwareAddress()); + } catch (IllegalArgumentException|NullPointerException|SocketException e) { + return null; + } + } +} diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java index 725ddb9ccbca..9b75a509288f 100644 --- a/tests/net/java/android/net/apf/ApfTest.java +++ b/tests/net/java/android/net/apf/ApfTest.java @@ -35,6 +35,7 @@ import android.net.apf.ApfGenerator.Register; import android.net.ip.IpManager; import android.net.metrics.IpConnectivityLog; import android.net.metrics.RaEvent; +import android.net.util.InterfaceParams; import android.os.ConditionVariable; import android.os.Parcelable; import android.os.SystemClock; @@ -62,7 +63,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; -import java.net.NetworkInterface; import java.nio.ByteBuffer; import java.util.List; import java.util.Random; @@ -635,7 +635,7 @@ public class ApfTest { public TestApfFilter(ApfConfiguration config, IpManager.Callback ipManagerCallback, IpConnectivityLog log) throws Exception { - super(config, NetworkInterface.getByName("lo"), ipManagerCallback, log); + super(config, InterfaceParams.getByName("lo"), ipManagerCallback, log); } // Pretend an RA packet has been received and show it to ApfFilter. diff --git a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java index 54776dbd3c52..e65585f8ff0f 100644 --- a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java +++ b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.fail; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.when; +import android.net.util.InterfaceParams; import android.net.util.SharedLog; import android.os.Handler; import android.os.Looper; @@ -54,8 +55,8 @@ public class IpReachabilityMonitorTest { } IpReachabilityMonitor makeMonitor() { - return new IpReachabilityMonitor( - "fake0", 1, mHandler, mLog, mCallback, null, mDependencies); + final InterfaceParams ifParams = new InterfaceParams("fake0", 1, null); + return new IpReachabilityMonitor(ifParams, mHandler, mLog, mCallback, null, mDependencies); } @Test diff --git a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java index 38d3d74e64cf..f9b7ec8f0322 100644 --- a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java +++ b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java @@ -20,6 +20,7 @@ import static android.net.util.NetworkConstants.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.net.MacAddress; import android.support.test.runner.AndroidJUnit4; import android.support.test.filters.SmallTest; @@ -36,9 +37,7 @@ import libcore.util.HexEncoding; @RunWith(AndroidJUnit4.class) @SmallTest public class ConnectivityPacketSummaryTest { - private static final byte[] MYHWADDR = { - asByte(0x80), asByte(0x7a), asByte(0xbf), asByte(0x6f), asByte(0x48), asByte(0xf3) - }; + private static final MacAddress MYHWADDR = MacAddress.fromString("80:7a:bf:6f:48:f3"); private String getSummary(String hexBytes) { hexBytes = hexBytes.replaceAll("\\s+", ""); diff --git a/tests/net/java/android/net/util/InterfaceParamsTest.java b/tests/net/java/android/net/util/InterfaceParamsTest.java new file mode 100644 index 000000000000..21728afdd5de --- /dev/null +++ b/tests/net/java/android/net/util/InterfaceParamsTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class InterfaceParamsTest { + @Test + public void testNullInterfaceReturnsNull() { + assertNull(InterfaceParams.getByName(null)); + } + + @Test + public void testNonExistentInterfaceReturnsNull() { + assertNull(InterfaceParams.getByName("doesnotexist0")); + } + + @Test + public void testLoopback() { + final InterfaceParams ifParams = InterfaceParams.getByName("lo"); + assertNotNull(ifParams); + assertEquals("lo", ifParams.name); + assertTrue(ifParams.index > 0); + assertNotNull(ifParams.macAddr); + assertTrue(ifParams.defaultMtu >= NetworkConstants.ETHER_MTU); + } +} |