Merge "Handle downstream tethering interface addresses in MdnsSocketProvider"
diff --git a/framework/src/android/net/LinkAddress.java b/framework/src/android/net/LinkAddress.java
index d48b8c7..90f55b3 100644
--- a/framework/src/android/net/LinkAddress.java
+++ b/framework/src/android/net/LinkAddress.java
@@ -487,17 +487,23 @@
      */
     @SystemApi
     public boolean isGlobalPreferred() {
-        /**
-         * Note that addresses flagged as IFA_F_OPTIMISTIC are
-         * simultaneously flagged as IFA_F_TENTATIVE (when the tentative
-         * state has cleared either DAD has succeeded or failed, and both
-         * flags are cleared regardless).
-         */
-        int flags = getFlags();
         return (scope == RT_SCOPE_UNIVERSE
                 && !isIpv6ULA()
-                && (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
-                && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L));
+                && isPreferred());
+    }
+
+    /**
+     * Checks if the address is a preferred address.
+     *
+     * @hide
+     */
+    public boolean isPreferred() {
+        //  Note that addresses flagged as IFA_F_OPTIMISTIC are simultaneously flagged as
+        //  IFA_F_TENTATIVE (when the tentative state has cleared either DAD has succeeded or
+        //  failed, and both flags are cleared regardless).
+        int flags = getFlags();
+        return (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
+                && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L);
     }
 
     /**
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index a658791..c5104d8 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -1330,6 +1330,9 @@
         mDeps = deps;
 
         mMdnsSocketProvider = deps.makeMdnsSocketProvider(ctx, handler.getLooper());
+        // Netlink monitor starts on boot, and intentionally never stopped, to ensure that all
+        // address events are received.
+        handler.post(mMdnsSocketProvider::startNetLinkMonitor);
         mMdnsSocketClient =
                 new MdnsMultinetworkSocketClient(handler.getLooper(), mMdnsSocketProvider);
         mMdnsDiscoveryManager =
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
index 0952e88..8017ee0 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
@@ -36,10 +36,12 @@
 import android.os.Looper;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.CollectionUtils;
 import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
+import com.android.net.module.util.SharedLog;
 import com.android.server.connectivity.mdns.util.MdnsLogger;
 
 import java.io.IOException;
@@ -65,6 +67,7 @@
     // Note: mdnsresponder mDNSEmbeddedAPI.h uses 8940 for Ethernet jumbo frames.
     private static final int READ_BUFFER_SIZE = 2048;
     private static final MdnsLogger LOGGER = new MdnsLogger(TAG);
+    private static final int IFACE_IDX_NOT_EXIST = -1;
     @NonNull private final Context mContext;
     @NonNull private final Looper mLooper;
     @NonNull private final Handler mHandler;
@@ -81,6 +84,9 @@
             new ArrayMap<>();
     private final List<String> mLocalOnlyInterfaces = new ArrayList<>();
     private final List<String> mTetheredInterfaces = new ArrayList<>();
+    // mIfaceIdxToLinkProperties should not be cleared in maybeStopMonitoringSockets() because
+    // the netlink monitor is never stop and the old states must be kept.
+    private final SparseArray<LinkProperties> mIfaceIdxToLinkProperties = new SparseArray<>();
     private final byte[] mPacketReadBuffer = new byte[READ_BUFFER_SIZE];
     private boolean mMonitoringSockets = false;
     private boolean mRequestStop = false;
@@ -126,8 +132,8 @@
             }
         };
 
-        mSocketNetlinkMonitor = SocketNetLinkMonitorFactory.createNetLinkMonitor(mHandler,
-                LOGGER.mLog);
+        mSocketNetlinkMonitor = mDependencies.createSocketNetlinkMonitor(mHandler, LOGGER.mLog,
+                new NetLinkMessageProcessor());
     }
 
     /**
@@ -148,8 +154,83 @@
                 @NonNull byte[] packetReadBuffer) throws IOException {
             return new MdnsInterfaceSocket(networkInterface, port, looper, packetReadBuffer);
         }
-    }
 
+        /*** Get network interface by given interface name */
+        public int getNetworkInterfaceIndexByName(@NonNull final String ifaceName) {
+            final NetworkInterface iface;
+            try {
+                iface = NetworkInterface.getByName(ifaceName);
+            } catch (SocketException e) {
+                Log.e(TAG, "Error querying interface", e);
+                return IFACE_IDX_NOT_EXIST;
+            }
+            if (iface == null) {
+                Log.e(TAG, "Interface not found: " + ifaceName);
+                return IFACE_IDX_NOT_EXIST;
+            }
+            return iface.getIndex();
+        }
+        /*** Creates a SocketNetlinkMonitor */
+        public ISocketNetLinkMonitor createSocketNetlinkMonitor(@NonNull final Handler handler,
+                @NonNull final SharedLog log,
+                @NonNull final NetLinkMonitorCallBack cb) {
+            return SocketNetLinkMonitorFactory.createNetLinkMonitor(handler, log, cb);
+        }
+    }
+    /**
+     * The callback interface for the netlink monitor messages.
+     */
+    public interface NetLinkMonitorCallBack {
+        /**
+         * Handles the interface address add or update.
+         */
+        void addOrUpdateInterfaceAddress(int ifaceIdx, @NonNull LinkAddress newAddress);
+
+
+        /**
+         * Handles the interface address delete.
+         */
+        void deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress);
+    }
+    private class NetLinkMessageProcessor implements NetLinkMonitorCallBack {
+
+        @Override
+        public void addOrUpdateInterfaceAddress(int ifaceIdx,
+                @NonNull final LinkAddress newAddress) {
+
+            LinkProperties linkProperties;
+            linkProperties = mIfaceIdxToLinkProperties.get(ifaceIdx);
+            if (linkProperties == null) {
+                linkProperties = new LinkProperties();
+                mIfaceIdxToLinkProperties.put(ifaceIdx, linkProperties);
+            }
+            boolean updated = linkProperties.addLinkAddress(newAddress);
+
+            if (!updated) {
+                return;
+            }
+            maybeUpdateTetheringSocketAddress(ifaceIdx, linkProperties.getLinkAddresses());
+        }
+
+        @Override
+        public void deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress) {
+            LinkProperties linkProperties;
+            boolean updated = false;
+            linkProperties = mIfaceIdxToLinkProperties.get(ifaceIdx);
+            if (linkProperties != null) {
+                updated = linkProperties.removeLinkAddress(deleteAddress);
+                if (linkProperties.getLinkAddresses().isEmpty()) {
+                    mIfaceIdxToLinkProperties.remove(ifaceIdx);
+                }
+            }
+
+            if (linkProperties == null || !updated) {
+                return;
+            }
+            maybeUpdateTetheringSocketAddress(ifaceIdx, linkProperties.getLinkAddresses());
+
+        }
+    }
     /*** Data class for storing socket related info  */
     private static class SocketInfo {
         final MdnsInterfaceSocket mSocket;
@@ -190,6 +271,15 @@
         }
         mMonitoringSockets = true;
     }
+    /**
+     * Start netlink monitor.
+     */
+    public void startNetLinkMonitor() {
+        ensureRunningOnHandlerThread(mHandler);
+        if (mSocketNetlinkMonitor.isSupported()) {
+            mSocketNetlinkMonitor.startMonitoring();
+        }
+    }
 
     private void maybeStopMonitoringSockets() {
         if (!mMonitoringSockets) return; // Already unregistered.
@@ -203,10 +293,6 @@
             final TetheringManager tetheringManager = mContext.getSystemService(
                     TetheringManager.class);
             tetheringManager.unregisterTetheringEventCallback(mTetheringEventCallback);
-
-            if (mSocketNetlinkMonitor.isSupported()) {
-                mHandler.post(mSocketNetlinkMonitor::stopMonitoring);
-            }
             // Clear all saved status.
             mActiveNetworksLinkProperties.clear();
             mNetworkSockets.clear();
@@ -215,6 +301,8 @@
             mTetheredInterfaces.clear();
             mMonitoringSockets = false;
         }
+        // The netlink monitor is not stopped here because the MdnsSocketProvider need to listen
+        // to all the netlink updates when the system is up and running.
     }
 
     /*** Request to stop monitoring sockets and unregister callbacks */
@@ -259,21 +347,38 @@
         if (socketInfo == null) {
             createSocket(networkKey, lp);
         } else {
-            // Update the addresses of this socket.
-            final List<LinkAddress> addresses = lp.getLinkAddresses();
-            socketInfo.mAddresses.clear();
-            socketInfo.mAddresses.addAll(addresses);
-            // Try to join the group again.
-            socketInfo.mSocket.joinGroup(addresses);
-
-            notifyAddressesChanged(network, socketInfo.mSocket, lp);
+            updateSocketInfoAddress(network, socketInfo, lp.getLinkAddresses());
+        }
+    }
+    private void maybeUpdateTetheringSocketAddress(int ifaceIndex,
+            @NonNull final List<LinkAddress> updatedAddresses) {
+        for (int i = 0; i < mTetherInterfaceSockets.size(); ++i) {
+            String tetheringInterfaceName = mTetherInterfaceSockets.keyAt(i);
+            if (mDependencies.getNetworkInterfaceIndexByName(tetheringInterfaceName)
+                    == ifaceIndex) {
+                updateSocketInfoAddress(null /* network */,
+                        mTetherInterfaceSockets.valueAt(i), updatedAddresses);
+                return;
+            }
         }
     }
 
-    private static LinkProperties createLPForTetheredInterface(String interfaceName) {
-        final LinkProperties linkProperties = new LinkProperties();
+    private void updateSocketInfoAddress(@Nullable final Network network,
+            @NonNull final SocketInfo socketInfo,
+            @NonNull final List<LinkAddress> addresses) {
+        // Update the addresses of this socket.
+        socketInfo.mAddresses.clear();
+        socketInfo.mAddresses.addAll(addresses);
+        // Try to join the group again.
+        socketInfo.mSocket.joinGroup(addresses);
+
+        notifyAddressesChanged(network, socketInfo.mSocket, addresses);
+    }
+    private LinkProperties createLPForTetheredInterface(@NonNull final String interfaceName,
+            int ifaceIndex) {
+        final LinkProperties linkProperties =
+                new LinkProperties(mIfaceIdxToLinkProperties.get(ifaceIndex));
         linkProperties.setInterfaceName(interfaceName);
-        // TODO: Use NetlinkMonitor to update addresses for tethering interfaces.
         return linkProperties;
     }
 
@@ -292,7 +397,8 @@
         final CompareResult<String> interfaceDiff = new CompareResult<>(
                 current, updated);
         for (String name : interfaceDiff.added) {
-            createSocket(LOCAL_NET, createLPForTetheredInterface(name));
+            int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(name);
+            createSocket(LOCAL_NET, createLPForTetheredInterface(name, ifaceIndex));
         }
         for (String name : interfaceDiff.removed) {
             removeTetherInterfaceSocket(name);
@@ -332,14 +438,10 @@
             final MdnsInterfaceSocket socket = mDependencies.createMdnsInterfaceSocket(
                     networkInterface.getNetworkInterface(), MdnsConstants.MDNS_PORT, mLooper,
                     mPacketReadBuffer);
-            final List<LinkAddress> addresses;
+            final List<LinkAddress> addresses = lp.getLinkAddresses();
             if (networkKey == LOCAL_NET) {
-                addresses = CollectionUtils.map(
-                        networkInterface.getInterfaceAddresses(),
-                        i -> new LinkAddress(i.getAddress(), i.getNetworkPrefixLength()));
                 mTetherInterfaceSockets.put(interfaceName, new SocketInfo(socket, addresses));
             } else {
-                addresses = lp.getLinkAddresses();
                 mNetworkSockets.put(((NetworkAsKey) networkKey).mNetwork,
                         new SocketInfo(socket, addresses));
             }
@@ -422,12 +524,12 @@
     }
 
     private void notifyAddressesChanged(Network network, MdnsInterfaceSocket socket,
-            LinkProperties lp) {
+            List<LinkAddress> addresses) {
         for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) {
             final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i);
             if (isNetworkMatched(requestedNetwork, network)) {
                 mCallbacksToRequestedNetworks.keyAt(i)
-                        .onAddressesChanged(network, socket, lp.getLinkAddresses());
+                        .onAddressesChanged(network, socket, addresses);
             }
         }
     }
@@ -451,7 +553,10 @@
     private void retrieveAndNotifySocketFromInterface(String interfaceName, SocketCallback cb) {
         final SocketInfo socketInfo = mTetherInterfaceSockets.get(interfaceName);
         if (socketInfo == null) {
-            createSocket(LOCAL_NET, createLPForTetheredInterface(interfaceName));
+            int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(interfaceName);
+            createSocket(
+                    LOCAL_NET,
+                    createLPForTetheredInterface(interfaceName, ifaceIndex));
         } else {
             // Notify the socket for requested network.
             cb.onSocketCreated(
diff --git a/service-t/src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java b/service-t/src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java
index 8f6aecc..4650255 100644
--- a/service-t/src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java
+++ b/service-t/src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java
@@ -31,8 +31,8 @@
      * Creates a new netlink monitor.
      */
     public static ISocketNetLinkMonitor createNetLinkMonitor(@NonNull final Handler handler,
-            @NonNull SharedLog log) {
-        return new SocketNetlinkMonitor(handler, log);
+            @NonNull SharedLog log, @NonNull MdnsSocketProvider.NetLinkMonitorCallBack cb) {
+        return new SocketNetlinkMonitor(handler, log, cb);
     }
 
     private SocketNetLinkMonitorFactory() {
diff --git a/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java b/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java
index e053413..6395b53 100644
--- a/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java
+++ b/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java
@@ -17,28 +17,64 @@
 package com.android.server.connectivity.mdns.internal;
 
 import android.annotation.NonNull;
+import android.net.LinkAddress;
 import android.os.Handler;
 import android.system.OsConstants;
+import android.util.Log;
 
 import com.android.net.module.util.SharedLog;
 import com.android.net.module.util.ip.NetlinkMonitor;
 import com.android.net.module.util.netlink.NetlinkConstants;
 import com.android.net.module.util.netlink.NetlinkMessage;
+import com.android.net.module.util.netlink.RtNetlinkAddressMessage;
+import com.android.net.module.util.netlink.StructIfaddrMsg;
 import com.android.server.connectivity.mdns.ISocketNetLinkMonitor;
+import com.android.server.connectivity.mdns.MdnsSocketProvider;
 
 /**
  * The netlink monitor for MdnsSocketProvider.
  */
 public class SocketNetlinkMonitor extends NetlinkMonitor implements ISocketNetLinkMonitor {
 
-    public SocketNetlinkMonitor(@NonNull final Handler handler, @NonNull SharedLog log) {
-        super(handler, log, SocketNetlinkMonitor.class.getSimpleName(), OsConstants.NETLINK_ROUTE,
-                NetlinkConstants.RTMGRP_IPV4_IFADDR | NetlinkConstants.RTMGRP_IPV6_IFADDR);
-    }
+    public static final String TAG = SocketNetlinkMonitor.class.getSimpleName();
 
+    @NonNull
+    private final MdnsSocketProvider.NetLinkMonitorCallBack mCb;
+    public SocketNetlinkMonitor(@NonNull final Handler handler,
+            @NonNull SharedLog log,
+            @NonNull final MdnsSocketProvider.NetLinkMonitorCallBack cb) {
+        super(handler, log, TAG, OsConstants.NETLINK_ROUTE,
+                NetlinkConstants.RTMGRP_IPV4_IFADDR | NetlinkConstants.RTMGRP_IPV6_IFADDR);
+        mCb = cb;
+    }
     @Override
     public void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) {
+        if (nlMsg instanceof RtNetlinkAddressMessage) {
+            processRtNetlinkAddressMessage((RtNetlinkAddressMessage) nlMsg);
+        }
+    }
 
+    /**
+     * Process the RTM_NEWADDR and RTM_DELADDR netlink message.
+     */
+    private void processRtNetlinkAddressMessage(RtNetlinkAddressMessage msg) {
+        final StructIfaddrMsg ifaddrMsg = msg.getIfaddrHeader();
+        final LinkAddress la = new LinkAddress(msg.getIpAddress(), ifaddrMsg.prefixLen,
+                msg.getFlags(), ifaddrMsg.scope);
+        if (!la.isPreferred()) {
+            // Skip the unusable ip address.
+            return;
+        }
+        switch (msg.getHeader().nlmsg_type) {
+            case NetlinkConstants.RTM_NEWADDR:
+                mCb.addOrUpdateInterfaceAddress(ifaddrMsg.index, la);
+                break;
+            case NetlinkConstants.RTM_DELADDR:
+                mCb.deleteInterfaceAddress(ifaddrMsg.index, la);
+                break;
+            default:
+                Log.e(TAG, "Unknown rtnetlink address msg type " + msg.getHeader().nlmsg_type);
+        }
     }
 
     @Override
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
index d9420b8..2d73c98 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
@@ -21,6 +21,8 @@
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK;
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
 import static com.android.testutils.ContextUtils.mockService;
 
 import static org.junit.Assert.assertEquals;
@@ -30,6 +32,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doCallRealMethod;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -49,9 +52,19 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.system.OsConstants;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.net.module.util.ArrayTrackRecord;
+import com.android.net.module.util.SharedLog;
+import com.android.net.module.util.netlink.NetlinkConstants;
+import com.android.net.module.util.netlink.RtNetlinkAddressMessage;
+import com.android.net.module.util.netlink.StructIfaddrMsg;
+import com.android.net.module.util.netlink.StructNlMsgHdr;
 import com.android.server.connectivity.mdns.MdnsSocketProvider.Dependencies;
+import com.android.server.connectivity.mdns.internal.SocketNetlinkMonitor;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRunner;
 import com.android.testutils.HandlerUtils;
@@ -64,20 +77,28 @@
 import org.mockito.MockitoAnnotations;
 
 import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
 import java.util.Collections;
 import java.util.List;
 
 @RunWith(DevSdkIgnoreRunner.class)
 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
 public class MdnsSocketProviderTest {
+    private static final String TAG = MdnsSocketProviderTest.class.getSimpleName();
     private static final String TEST_IFACE_NAME = "test";
     private static final String LOCAL_ONLY_IFACE_NAME = "local_only";
     private static final String TETHERED_IFACE_NAME = "tethered";
+    private static final int TETHERED_IFACE_IDX = 32;
     private static final long DEFAULT_TIMEOUT = 2000L;
     private static final long NO_CALLBACK_TIMEOUT = 200L;
     private static final LinkAddress LINKADDRV4 = new LinkAddress("192.0.2.0/24");
     private static final LinkAddress LINKADDRV6 =
             new LinkAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64");
+
+    private static final LinkAddress LINKADDRV6_FLAG_CHANGE =
+            new LinkAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64", 1 /* flags */,
+                    0 /* scope */);
     private static final Network TEST_NETWORK = new Network(123);
     @Mock private Context mContext;
     @Mock private Dependencies mDeps;
@@ -91,6 +112,7 @@
     private NetworkCallback mNetworkCallback;
     private TetheringEventCallback mTetheringEventCallback;
 
+    private TestNetLinkMonitor mTestSocketNetLinkMonitor;
     @Before
     public void setUp() throws IOException {
         MockitoAnnotations.initMocks(this);
@@ -116,9 +138,21 @@
         doReturn(mTetheredIfaceWrapper).when(mDeps).getNetworkInterfaceByName(TETHERED_IFACE_NAME);
         doReturn(mock(MdnsInterfaceSocket.class))
                 .when(mDeps).createMdnsInterfaceSocket(any(), anyInt(), any(), any());
+        doReturn(TETHERED_IFACE_IDX).when(mDeps).getNetworkInterfaceIndexByName(
+                TETHERED_IFACE_NAME);
         final HandlerThread thread = new HandlerThread("MdnsSocketProviderTest");
         thread.start();
         mHandler = new Handler(thread.getLooper());
+
+        doReturn(mTestSocketNetLinkMonitor).when(mDeps).createSocketNetlinkMonitor(any(), any(),
+                any());
+        doAnswer(inv -> {
+            mTestSocketNetLinkMonitor = new TestNetLinkMonitor(inv.getArgument(0),
+                    inv.getArgument(1),
+                    inv.getArgument(2));
+            return mTestSocketNetLinkMonitor;
+        }).when(mDeps).createSocketNetlinkMonitor(any(), any(),
+                any());
         mSocketProvider = new MdnsSocketProvider(mContext, thread.getLooper(), mDeps);
     }
 
@@ -135,6 +169,23 @@
 
         mNetworkCallback = nwCallbackCaptor.getValue();
         mTetheringEventCallback = teCallbackCaptor.getValue();
+
+        mHandler.post(mSocketProvider::startNetLinkMonitor);
+        HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+    }
+
+    private static class TestNetLinkMonitor extends SocketNetlinkMonitor {
+        TestNetLinkMonitor(@NonNull Handler handler,
+                @NonNull SharedLog log,
+                @Nullable MdnsSocketProvider.NetLinkMonitorCallBack cb) {
+            super(handler, log, cb);
+        }
+
+        @Override
+        public void startMonitoring() { }
+
+        @Override
+        public void stopMonitoring() { }
     }
 
     private class TestSocketCallback implements MdnsSocketProvider.SocketCallback {
@@ -301,6 +352,87 @@
         testCallback3.expectedInterfaceDestroyedForNetwork(null /* network */);
     }
 
+    private RtNetlinkAddressMessage createNetworkAddressUpdateNetLink(
+            short msgType, LinkAddress linkAddress, int ifIndex, int flags) {
+        final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
+        nlmsghdr.nlmsg_type = msgType;
+        nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+        nlmsghdr.nlmsg_seq = 1;
+
+        InetAddress ip = linkAddress.getAddress();
+
+        final byte family =
+                (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
+        StructIfaddrMsg structIfaddrMsg = new StructIfaddrMsg(family,
+                (short) linkAddress.getPrefixLength(),
+                (short) linkAddress.getFlags(), (short) linkAddress.getScope(), ifIndex);
+
+        return new RtNetlinkAddressMessage(nlmsghdr, structIfaddrMsg, ip,
+                null /* structIfacacheInfo */, flags);
+    }
+
+    @Test
+    public void testDownstreamNetworkAddressUpdateFromNetlink() {
+        startMonitoringSockets();
+        final TestSocketCallback testCallbackAll = new TestSocketCallback();
+        mHandler.post(() -> mSocketProvider.requestSocket(null /* network */, testCallbackAll));
+        HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+
+        // Address add message arrived before the interface is created.
+        RtNetlinkAddressMessage addIpv4AddrMsg = createNetworkAddressUpdateNetLink(
+                NetlinkConstants.RTM_NEWADDR,
+                LINKADDRV4,
+                TETHERED_IFACE_IDX,
+                0 /* flags */);
+        mHandler.post(
+                () -> mTestSocketNetLinkMonitor.processNetlinkMessage(addIpv4AddrMsg,
+                        0 /* whenMs */));
+        HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+
+        // Interface is created.
+        mHandler.post(() -> mTetheringEventCallback.onTetheredInterfacesChanged(
+                List.of(TETHERED_IFACE_NAME)));
+        HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+        verify(mTetheredIfaceWrapper).getNetworkInterface();
+        testCallbackAll.expectedSocketCreatedForNetwork(null /* network */, List.of(LINKADDRV4));
+
+        // Old Address removed.
+        RtNetlinkAddressMessage removeIpv4AddrMsg = createNetworkAddressUpdateNetLink(
+                NetlinkConstants.RTM_DELADDR,
+                LINKADDRV4,
+                TETHERED_IFACE_IDX,
+                0 /* flags */);
+        mHandler.post(
+                () -> mTestSocketNetLinkMonitor.processNetlinkMessage(removeIpv4AddrMsg,
+                        0 /* whenMs */));
+        HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+        testCallbackAll.expectedAddressesChangedForNetwork(null /* network */, List.of());
+
+        // New address added.
+        RtNetlinkAddressMessage addIpv6AddrMsg = createNetworkAddressUpdateNetLink(
+                NetlinkConstants.RTM_NEWADDR,
+                LINKADDRV6,
+                TETHERED_IFACE_IDX,
+                0 /* flags */);
+        mHandler.post(() -> mTestSocketNetLinkMonitor.processNetlinkMessage(addIpv6AddrMsg,
+                0 /* whenMs */));
+        HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+        testCallbackAll.expectedAddressesChangedForNetwork(null /* network */, List.of(LINKADDRV6));
+
+        // Address updated
+        RtNetlinkAddressMessage updateIpv6AddrMsg = createNetworkAddressUpdateNetLink(
+                NetlinkConstants.RTM_NEWADDR,
+                LINKADDRV6,
+                TETHERED_IFACE_IDX,
+                1 /* flags */);
+        mHandler.post(
+                () -> mTestSocketNetLinkMonitor.processNetlinkMessage(updateIpv6AddrMsg,
+                        0 /* whenMs */));
+        HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+        testCallbackAll.expectedAddressesChangedForNetwork(null /* network */,
+                List.of(LINKADDRV6_FLAG_CHANGE));
+    }
+
     @Test
     public void testAddressesChanged() throws Exception {
         startMonitoringSockets();