Merge "Plumb WiFi multicast filter through to ApfFilter" into nyc-dev
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index ebbf991..194650b 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -147,10 +147,11 @@
     private boolean mMulticastFilter;
 
     private ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
-            IpManager.Callback ipManagerCallback) {
+            IpManager.Callback ipManagerCallback, boolean multicastFilter) {
         mApfCapabilities = apfCapabilities;
         mIpManagerCallback = ipManagerCallback;
         mNetworkInterface = networkInterface;
+        mMulticastFilter = multicastFilter;
 
         maybeStartFilter();
     }
@@ -752,7 +753,8 @@
      * filtering using APF programs.
      */
     public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
-            NetworkInterface networkInterface, IpManager.Callback ipManagerCallback) {
+            NetworkInterface networkInterface, IpManager.Callback ipManagerCallback,
+            boolean multicastFilter) {
         if (apfCapabilities == null || networkInterface == null) return null;
         if (apfCapabilities.apfVersionSupported == 0) return null;
         if (apfCapabilities.maximumApfProgramSize < 512) {
@@ -768,7 +770,7 @@
             Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
             return null;
         }
-        return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback);
+        return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback, multicastFilter);
     }
 
     public synchronized void shutdown() {
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index d10834a..ecf46c8 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -116,6 +116,10 @@
 
         // Install an APF program to filter incoming packets.
         public void installPacketFilter(byte[] filter) {}
+
+        // If multicast filtering cannot be accomplished with APF, this function will be called to
+        // actuate multicast filtering using another means.
+        public void setFallbackMulticastFilter(boolean enabled) {}
     }
 
     public static class WaitForProvisioningCallback extends Callback {
@@ -222,6 +226,7 @@
     private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 5;
     private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 6;
     private static final int CMD_UPDATE_HTTP_PROXY = 7;
+    private static final int CMD_SET_MULTICAST_FILTER = 8;
 
     private static final int MAX_LOG_RECORDS = 1000;
 
@@ -258,6 +263,7 @@
     private String mTcpBufferSizes;
     private ProxyInfo mHttpProxy;
     private ApfFilter mApfFilter;
+    private boolean mMulticastFiltering;
 
     /**
      * Member variables accessed both from within the StateMachine thread
@@ -390,6 +396,14 @@
         sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
     }
 
+    /**
+     * Enable or disable the multicast filter.  Attempts to use APF to accomplish the filtering,
+     * if not, Callback.setFallbackMulticastFilter() is called.
+     */
+    public void setMulticastFilter(boolean enabled) {
+        sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
+    }
+
     public LinkProperties getLinkProperties() {
         synchronized (mLock) {
             return new LinkProperties(mLinkProperties);
@@ -729,6 +743,10 @@
                     handleLinkPropertiesUpdate(NO_CALLBACKS);
                     break;
 
+                case CMD_SET_MULTICAST_FILTER:
+                    mMulticastFiltering = (boolean) msg.obj;
+                    break;
+
                 case DhcpClient.CMD_ON_QUIT:
                     // Everything is already stopped.
                     Log.e(mTag, "Unexpected CMD_ON_QUIT (already stopped).");
@@ -769,7 +787,10 @@
         @Override
         public void enter() {
             mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
-                    mCallback);
+                    mCallback, mMulticastFiltering);
+            // TODO: investigate the effects of any multicast filtering racing/interfering with the
+            // rest of this IP configuration startup.
+            if (mApfFilter == null) mCallback.setFallbackMulticastFilter(mMulticastFiltering);
             // Set privacy extensions.
             try {
                 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
@@ -882,6 +903,16 @@
                     handleLinkPropertiesUpdate(SEND_CALLBACKS);
                     break;
 
+                case CMD_SET_MULTICAST_FILTER: {
+                    mMulticastFiltering = (boolean) msg.obj;
+                    if (mApfFilter != null) {
+                        mApfFilter.setMulticastFilter(mMulticastFiltering);
+                    } else {
+                        mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+                    }
+                    break;
+                }
+
                 case DhcpClient.CMD_PRE_DHCP_ACTION:
                     if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); }
                     if (mConfiguration.mRequestedPreDhcpAction) {