Loading packages/Tethering/src/android/net/ip/IpServer.java +18 −3 Original line number Diff line number Diff line Loading @@ -810,7 +810,7 @@ public class IpServer extends StateMachine { rule.dstMac.toByteArray()); mIpv6ForwardingRules.put(rule.address, rule); } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Could not add IPv6 downstream rule: " + e); mLog.e("Could not add IPv6 downstream rule: ", e); } } Loading @@ -821,10 +821,17 @@ public class IpServer extends StateMachine { mIpv6ForwardingRules.remove(rule.address); } } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Could not remove IPv6 downstream rule: " + e); mLog.e("Could not remove IPv6 downstream rule: ", e); } } private void clearIpv6ForwardingRules() { for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) { removeIpv6ForwardingRule(rule, false /*removeFromMap*/); } mIpv6ForwardingRules.clear(); } // Convenience method to replace a rule with the same rule on a new upstream interface. // Allows replacing the rules in one iteration pass without ConcurrentModificationExceptions. // Relies on the fact that rules are in a map indexed by IP address. Loading @@ -837,6 +844,12 @@ public class IpServer extends StateMachine { // changes or if a neighbor event is received. private void updateIpv6ForwardingRules(int prevUpstreamIfindex, int upstreamIfindex, NeighborEvent e) { // If we no longer have an upstream, clear forwarding rules and do nothing else. if (upstreamIfindex == 0) { clearIpv6ForwardingRules(); return; } // If the upstream interface has changed, remove all rules and re-add them with the new // upstream interface. if (prevUpstreamIfindex != upstreamIfindex) { Loading @@ -846,13 +859,14 @@ public class IpServer extends StateMachine { } // If we're here to process a NeighborEvent, do so now. // mInterfaceParams must be non-null or the event would not have arrived. if (e == null) return; if (!(e.ip instanceof Inet6Address) || e.ip.isMulticastAddress() || e.ip.isLoopbackAddress() || e.ip.isLinkLocalAddress()) { return; } Ipv6ForwardingRule rule = new Ipv6ForwardingRule(mLastIPv6UpstreamIfindex, Ipv6ForwardingRule rule = new Ipv6ForwardingRule(upstreamIfindex, mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr, e.macAddr); if (e.isValid()) { Loading Loading @@ -1095,6 +1109,7 @@ public class IpServer extends StateMachine { for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname); mUpstreamIfaceSet = null; clearIpv6ForwardingRules(); } private void cleanupUpstreamInterface(String upstreamIface) { Loading packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +49 −2 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; Loading Loading @@ -546,9 +547,9 @@ public class IpServerTest { reset(mNetd); // Link-local and multicast neighbors are ignored. recvNewNeigh(notMyIfindex, neighLL, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighLL, NUD_REACHABLE, macA); verifyNoMoreInteractions(mNetd); recvNewNeigh(notMyIfindex, neighMC, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighMC, NUD_REACHABLE, macA); verifyNoMoreInteractions(mNetd); // A neighbor that is no longer valid causes the rule to be removed. Loading Loading @@ -578,6 +579,52 @@ public class IpServerTest { eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress())); reset(mNetd); // When the upstream is lost, rules are removed. dispatchTetherConnectionChanged(null, null); verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2), eq(neighA.getAddress())); verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2), eq(neighB.getAddress())); reset(mNetd); // If the upstream is IPv4-only, no rules are added. dispatchTetherConnectionChanged(UPSTREAM_IFACE); reset(mNetd); recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); verifyNoMoreInteractions(mNetd); // Rules can be added again once upstream IPv6 connectivity is available. lp.setInterfaceName(UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); verify(mNetd, never()).tetherRuleAddDownstreamIpv6(anyInt(), anyInt(), eq(neighA.getAddress()), any(), any()); // If upstream IPv6 connectivity is lost, rules are removed. reset(mNetd); dispatchTetherConnectionChanged(UPSTREAM_IFACE, null); verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress())); // When the interface goes down, rules are removed. lp.setInterfaceName(UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp); recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray())); verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); reset(mNetd); mIpServer.stop(); mLooper.dispatchAll(); verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress())); verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress())); reset(mNetd); } private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception { Loading Loading
packages/Tethering/src/android/net/ip/IpServer.java +18 −3 Original line number Diff line number Diff line Loading @@ -810,7 +810,7 @@ public class IpServer extends StateMachine { rule.dstMac.toByteArray()); mIpv6ForwardingRules.put(rule.address, rule); } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Could not add IPv6 downstream rule: " + e); mLog.e("Could not add IPv6 downstream rule: ", e); } } Loading @@ -821,10 +821,17 @@ public class IpServer extends StateMachine { mIpv6ForwardingRules.remove(rule.address); } } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Could not remove IPv6 downstream rule: " + e); mLog.e("Could not remove IPv6 downstream rule: ", e); } } private void clearIpv6ForwardingRules() { for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) { removeIpv6ForwardingRule(rule, false /*removeFromMap*/); } mIpv6ForwardingRules.clear(); } // Convenience method to replace a rule with the same rule on a new upstream interface. // Allows replacing the rules in one iteration pass without ConcurrentModificationExceptions. // Relies on the fact that rules are in a map indexed by IP address. Loading @@ -837,6 +844,12 @@ public class IpServer extends StateMachine { // changes or if a neighbor event is received. private void updateIpv6ForwardingRules(int prevUpstreamIfindex, int upstreamIfindex, NeighborEvent e) { // If we no longer have an upstream, clear forwarding rules and do nothing else. if (upstreamIfindex == 0) { clearIpv6ForwardingRules(); return; } // If the upstream interface has changed, remove all rules and re-add them with the new // upstream interface. if (prevUpstreamIfindex != upstreamIfindex) { Loading @@ -846,13 +859,14 @@ public class IpServer extends StateMachine { } // If we're here to process a NeighborEvent, do so now. // mInterfaceParams must be non-null or the event would not have arrived. if (e == null) return; if (!(e.ip instanceof Inet6Address) || e.ip.isMulticastAddress() || e.ip.isLoopbackAddress() || e.ip.isLinkLocalAddress()) { return; } Ipv6ForwardingRule rule = new Ipv6ForwardingRule(mLastIPv6UpstreamIfindex, Ipv6ForwardingRule rule = new Ipv6ForwardingRule(upstreamIfindex, mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr, e.macAddr); if (e.isValid()) { Loading Loading @@ -1095,6 +1109,7 @@ public class IpServer extends StateMachine { for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname); mUpstreamIfaceSet = null; clearIpv6ForwardingRules(); } private void cleanupUpstreamInterface(String upstreamIface) { Loading
packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +49 −2 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; Loading Loading @@ -546,9 +547,9 @@ public class IpServerTest { reset(mNetd); // Link-local and multicast neighbors are ignored. recvNewNeigh(notMyIfindex, neighLL, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighLL, NUD_REACHABLE, macA); verifyNoMoreInteractions(mNetd); recvNewNeigh(notMyIfindex, neighMC, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighMC, NUD_REACHABLE, macA); verifyNoMoreInteractions(mNetd); // A neighbor that is no longer valid causes the rule to be removed. Loading Loading @@ -578,6 +579,52 @@ public class IpServerTest { eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress())); reset(mNetd); // When the upstream is lost, rules are removed. dispatchTetherConnectionChanged(null, null); verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2), eq(neighA.getAddress())); verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2), eq(neighB.getAddress())); reset(mNetd); // If the upstream is IPv4-only, no rules are added. dispatchTetherConnectionChanged(UPSTREAM_IFACE); reset(mNetd); recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); verifyNoMoreInteractions(mNetd); // Rules can be added again once upstream IPv6 connectivity is available. lp.setInterfaceName(UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); verify(mNetd, never()).tetherRuleAddDownstreamIpv6(anyInt(), anyInt(), eq(neighA.getAddress()), any(), any()); // If upstream IPv6 connectivity is lost, rules are removed. reset(mNetd); dispatchTetherConnectionChanged(UPSTREAM_IFACE, null); verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress())); // When the interface goes down, rules are removed. lp.setInterfaceName(UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp); recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray())); verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray())); reset(mNetd); mIpServer.stop(); mLooper.dispatchAll(); verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress())); verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress())); reset(mNetd); } private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception { Loading