am 558aeb90: Merge "Make NetworkCapabilities publicly immutable." into lmp-preview-dev

* commit '558aeb901144fac460575402e38fc8baa2da83eb':
  Make NetworkCapabilities publicly immutable.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 65d4726..ff90e78 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -898,6 +898,7 @@
                 case NetworkCapabilities.NET_CAPABILITY_IMS:
                 case NetworkCapabilities.NET_CAPABILITY_RCS:
                 case NetworkCapabilities.NET_CAPABILITY_XCAP:
+                case NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED: //there by default
                     continue;
                 default:
                     // At least one capability usually provided by unrestricted
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
new file mode 100644
index 0000000..dfe0384
--- /dev/null
+++ b/core/java/android/net/IpPrefix.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2014 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;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+/**
+ * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a
+ * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of
+ * information:
+ *
+ * <ul>
+ * <li>A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix.
+ * <li>A prefix length. This specifies the length of the prefix by specifing the number of bits
+ *     in the IP address, starting from the most significant bit in network byte order, that
+ *     are constant for all addresses in the prefix.
+ * </ul>
+ *
+ * For example, the prefix <code>192.0.2.0/24</code> covers the 256 IPv4 addresses from
+ * <code>192.0.2.0</code> to <code>192.0.2.255</code>, inclusive, and the prefix
+ * <code>2001:db8:1:2</code>  covers the 2^64 IPv6 addresses from <code>2001:db8:1:2::</code> to
+ * <code>2001:db8:1:2:ffff:ffff:ffff:ffff</code>, inclusive.
+ *
+ * Objects of this class are immutable.
+ */
+public class IpPrefix implements Parcelable {
+    private final byte[] address;  // network byte order
+    private final int prefixLength;
+
+    /**
+     * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in
+     * network byte order and a prefix length.
+     *
+     * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long.
+     * @param prefixLength the prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
+     *
+     * @hide
+     */
+    public IpPrefix(byte[] address, int prefixLength) {
+        if (address.length != 4 && address.length != 16) {
+            throw new IllegalArgumentException(
+                    "IpPrefix has " + address.length + " bytes which is neither 4 nor 16");
+        }
+        if (prefixLength < 0 || prefixLength > (address.length * 8)) {
+            throw new IllegalArgumentException("IpPrefix with " + address.length +
+                    " bytes has invalid prefix length " + prefixLength);
+        }
+        this.address = address.clone();
+        this.prefixLength = prefixLength;
+        // TODO: Validate that the non-prefix bits are zero
+    }
+
+    /**
+     * @hide
+     */
+    public IpPrefix(InetAddress address, int prefixLength) {
+        this(address.getAddress(), prefixLength);
+    }
+
+    /**
+     * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two
+     * objects are equal if they have the same startAddress and prefixLength.
+     *
+     * @param obj the object to be tested for equality.
+     * @return {@code true} if both objects are equal, {@code false} otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof IpPrefix)) {
+            return false;
+        }
+        IpPrefix that = (IpPrefix) obj;
+        return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength;
+    }
+
+    /**
+     * Gets the hashcode of the represented IP prefix.
+     *
+     * @return the appropriate hashcode value.
+     */
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(address) + 11 * prefixLength;
+    }
+
+    /**
+     * Returns a copy of the first IP address in the prefix. Modifying the returned object does not
+     * change this object's contents.
+     *
+     * @return the address in the form of a byte array.
+     */
+    public InetAddress getAddress() {
+        try {
+            return InetAddress.getByAddress(address);
+        } catch (UnknownHostException e) {
+            // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte
+            // array is the wrong length, but we check that in the constructor.
+            return null;
+        }
+    }
+
+    /**
+     * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth
+     * element). Modifying the returned array does not change this object's contents.
+     *
+     * @return the address in the form of a byte array.
+     */
+    public byte[] getRawAddress() {
+        return address.clone();
+    }
+
+    /**
+     * Returns the prefix length of this {@code IpAddress}.
+     *
+     * @return the prefix length.
+     */
+    public int getPrefixLength() {
+        return prefixLength;
+    }
+
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeByteArray(address);
+        dest.writeInt(prefixLength);
+    }
+
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
+    public static final Creator<IpPrefix> CREATOR =
+            new Creator<IpPrefix>() {
+                public IpPrefix createFromParcel(Parcel in) {
+                    byte[] address = in.createByteArray();
+                    int prefixLength = in.readInt();
+                    return new IpPrefix(address, prefixLength);
+                }
+
+                public IpPrefix[] newArray(int size) {
+                    return new IpPrefix[size];
+                }
+            };
+}
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index d07c0b6..5246078 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -39,18 +39,13 @@
  * <ul>
  * <li>An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}).
  * The address must be unicast, as multicast addresses cannot be assigned to interfaces.
- * <li>Address flags: A bitmask of {@code IFA_F_*} values representing properties
- * of the address.
- * <li>Address scope: An integer defining the scope in which the address is unique (e.g.,
- * {@code RT_SCOPE_LINK} or {@code RT_SCOPE_SITE}).
- * <ul>
- *<p>
- * When constructing a {@code LinkAddress}, the IP address and prefix are required. The flags and
- * scope are optional. If they are not specified, the flags are set to zero, and the scope will be
- * determined based on the IP address (e.g., link-local addresses will be created with a scope of
- * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE},
- * etc.) If they are specified, they are not checked for validity.
- *
+ * <li>Address flags: A bitmask of {@code OsConstants.IFA_F_*} values representing properties
+ * of the address (e.g., {@code android.system.OsConstants.IFA_F_OPTIMISTIC}).
+ * <li>Address scope: One of the {@code OsConstants.IFA_F_*} values; defines the scope in which
+ * the address is unique (e.g.,
+ * {@code android.system.OsConstants.RT_SCOPE_LINK} or
+ * {@code android.system.OsConstants.RT_SCOPE_UNIVERSE}).
+ * </ul>
  */
 public class LinkAddress implements Parcelable {
     /**
@@ -202,7 +197,9 @@
 
     /**
      * Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if
-     * their address, prefix length, flags and scope are equal.
+     * their address, prefix length, flags and scope are equal. Thus, for example, two addresses
+     * that have the same address and prefix length are not equal if one of them is deprecated and
+     * the other is not.
      *
      * @param obj the object to be tested for equality.
      * @return {@code true} if both objects are equal, {@code false} otherwise.
@@ -236,6 +233,7 @@
      * @param other the {@code LinkAddress} to compare to.
      * @return {@code true} if both objects have the same address and prefix length, {@code false}
      * otherwise.
+     * @hide
      */
     public boolean isSameAddressAs(LinkAddress other) {
         return address.equals(other.address) && prefixLength == other.prefixLength;
@@ -251,11 +249,20 @@
     /**
      * Returns the prefix length of this {@code LinkAddress}.
      */
-    public int getNetworkPrefixLength() {
+    public int getPrefixLength() {
         return prefixLength;
     }
 
     /**
+     * Returns the prefix length of this {@code LinkAddress}.
+     * TODO: Delete all callers and remove in favour of getPrefixLength().
+     * @hide
+     */
+    public int getNetworkPrefixLength() {
+        return getPrefixLength();
+    }
+
+    /**
      * Returns the flags of this {@code LinkAddress}.
      */
     public int getFlags() {
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index cff9025..bb05936 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -77,9 +77,15 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public LinkProperties() {
     }
 
+    /**
+     * @hide
+     */
     public LinkProperties(LinkProperties source) {
         if (source != null) {
             mIfaceName = source.getInterfaceName();
@@ -267,7 +273,7 @@
     }
 
     /**
-     * Returns all the {@link LinkAddress} for DNS servers on this link.
+     * Returns all the {@link InetAddress} for DNS servers on this link.
      *
      * @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on
      *         this link.
@@ -477,12 +483,12 @@
 
         String domainName = "Domains: " + mDomains;
 
-        String mtu = "MTU: " + mMtu;
+        String mtu = " MTU: " + mMtu;
 
         String routes = " Routes: [";
         for (RouteInfo route : mRoutes) routes += route.toString() + ",";
         routes += "] ";
-        String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
+        String proxy = (mHttpProxy == null ? "" : " HttpProxy: " + mHttpProxy.toString() + " ");
 
         String stacked = "";
         if (mStackedLinks.values().size() > 0) {
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 7e8b1f1..3d0874b 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -80,6 +80,11 @@
      */
     public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
 
+    /* centralize place where base network score, and network score scaling, will be
+     * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE
+     */
+    public static final int WIFI_BASE_SCORE = 60;
+
     /**
      * Sent by the NetworkAgent to ConnectivityService to pass the current
      * network score.
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index ad8e4f7..8b42bcd 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -35,10 +35,10 @@
  *
  * A route contains three pieces of information:
  * <ul>
- * <li>a destination {@link LinkAddress} for directly-connected subnets.  If this is
- *     {@code null} it indicates a default route of the address family (IPv4 or IPv6)
+ * <li>a destination {@link IpPrefix} specifying the network destinations covered by this route.
+ *     If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6)
  *     implied by the gateway IP address.
- * <li>a gateway {@link InetAddress} for default routes.  If this is {@code null} it
+ * <li>a gateway {@link InetAddress} indicating the next hop to use.  If this is {@code null} it
  *     indicates a directly-connected route.
  * <li>an interface (which may be unspecified).
  * </ul>
@@ -49,6 +49,7 @@
 public class RouteInfo implements Parcelable {
     /**
      * The IP destination address for this route.
+     * TODO: Make this an IpPrefix.
      */
     private final LinkAddress mDestination;
 
@@ -80,6 +81,19 @@
      * @param destination the destination prefix
      * @param gateway the IP address to route packets through
      * @param iface the interface name to send packets on
+     *
+     * TODO: Convert to use IpPrefix.
+     *
+     * @hide
+     */
+    public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
+        this(destination == null ? null :
+                new LinkAddress(destination.getAddress(), destination.getPrefixLength()),
+                gateway, iface);
+    }
+
+    /**
+     * @hide
      */
     public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
         if (destination == null) {
@@ -105,7 +119,7 @@
         mHasGateway = (!gateway.isAnyLocalAddress());
 
         mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
-                destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
+                destination.getPrefixLength()), destination.getPrefixLength());
         if ((destination.getAddress() instanceof Inet4Address &&
                  (gateway instanceof Inet4Address == false)) ||
                 (destination.getAddress() instanceof Inet6Address &&
@@ -128,8 +142,17 @@
      * <p>
      * Destination and gateway may not both be null.
      *
-     * @param destination the destination address and prefix in a {@link LinkAddress}
+     * @param destination the destination address and prefix in an {@link IpPrefix}
      * @param gateway the {@link InetAddress} to route packets through
+     *
+     * @hide
+     */
+    public RouteInfo(IpPrefix destination, InetAddress gateway) {
+        this(destination, gateway, null);
+    }
+
+    /**
+     * @hide
      */
     public RouteInfo(LinkAddress destination, InetAddress gateway) {
         this(destination, gateway, null);
@@ -139,16 +162,27 @@
      * Constructs a default {@code RouteInfo} object.
      *
      * @param gateway the {@link InetAddress} to route packets through
+     *
+     * @hide
      */
     public RouteInfo(InetAddress gateway) {
-        this(null, gateway, null);
+        this((LinkAddress) null, gateway, null);
     }
 
     /**
      * Constructs a {@code RouteInfo} object representing a direct connected subnet.
      *
-     * @param destination the {@link LinkAddress} describing the address and prefix
+     * @param destination the {@link IpPrefix} describing the address and prefix
      *                    length of the subnet.
+     *
+     * @hide
+     */
+    public RouteInfo(IpPrefix destination) {
+        this(destination, null, null);
+    }
+
+    /**
+     * @hide
      */
     public RouteInfo(LinkAddress destination) {
         this(destination, null, null);
@@ -176,29 +210,37 @@
 
     private boolean isHost() {
         return (mDestination.getAddress() instanceof Inet4Address &&
-                mDestination.getNetworkPrefixLength() == 32) ||
+                mDestination.getPrefixLength() == 32) ||
                (mDestination.getAddress() instanceof Inet6Address &&
-                mDestination.getNetworkPrefixLength() == 128);
+                mDestination.getPrefixLength() == 128);
     }
 
     private boolean isDefault() {
         boolean val = false;
         if (mGateway != null) {
             if (mGateway instanceof Inet4Address) {
-                val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
+                val = (mDestination == null || mDestination.getPrefixLength() == 0);
             } else {
-                val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
+                val = (mDestination == null || mDestination.getPrefixLength() == 0);
             }
         }
         return val;
     }
 
     /**
-     * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}.
+     * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}.
      *
-     * @return {@link LinkAddress} specifying the destination.  This is never {@code null}.
+     * @return {@link IpPrefix} specifying the destination.  This is never {@code null}.
      */
-    public LinkAddress getDestination() {
+    public IpPrefix getDestination() {
+        return new IpPrefix(mDestination.getAddress(), mDestination.getPrefixLength());
+    }
+
+    /**
+     * TODO: Convert callers to use IpPrefix and then remove.
+     * @hide
+     */
+    public LinkAddress getDestinationLinkAddress() {
         return mDestination;
     }
 
@@ -233,7 +275,8 @@
     /**
      * Indicates if this route is a host route (ie, matches only a single host address).
      *
-     * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6.
+     * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6,
+     * respectively.
      * @hide
      */
     public boolean isHostRoute() {
@@ -263,7 +306,7 @@
 
         // match the route destination and destination with prefix length
         InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
-                mDestination.getNetworkPrefixLength());
+                mDestination.getPrefixLength());
 
         return mDestination.getAddress().equals(dstNet);
     }
@@ -285,8 +328,8 @@
         for (RouteInfo route : routes) {
             if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
                 if ((bestRoute != null) &&
-                        (bestRoute.mDestination.getNetworkPrefixLength() >=
-                        route.mDestination.getNetworkPrefixLength())) {
+                        (bestRoute.mDestination.getPrefixLength() >=
+                        route.mDestination.getPrefixLength())) {
                     continue;
                 }
                 if (route.matches(dest)) bestRoute = route;
@@ -295,13 +338,22 @@
         return bestRoute;
     }
 
+    /**
+     * Returns a human-readable description of this object.
+     */
     public String toString() {
         String val = "";
         if (mDestination != null) val = mDestination.toString();
-        if (mGateway != null) val += " -> " + mGateway.getHostAddress();
+        val += " ->";
+        if (mGateway != null) val += " " + mGateway.getHostAddress();
+        if (mInterface != null) val += " " + mInterface;
         return val;
     }
 
+    /**
+     * Compares this RouteInfo object against the specified object and indicates if they are equal.
+     * @return {@code true} if the objects are equal, {@code false} otherwise.
+     */
     public boolean equals(Object obj) {
         if (this == obj) return true;
 
@@ -309,11 +361,14 @@
 
         RouteInfo target = (RouteInfo) obj;
 
-        return Objects.equals(mDestination, target.getDestination()) &&
+        return Objects.equals(mDestination, target.getDestinationLinkAddress()) &&
                 Objects.equals(mGateway, target.getGateway()) &&
                 Objects.equals(mInterface, target.getInterface());
     }
 
+    /**
+     *  Returns a hashcode for this <code>RouteInfo</code> object.
+     */
     public int hashCode() {
         return (mDestination == null ? 0 : mDestination.hashCode() * 41)
                 + (mGateway == null ? 0 :mGateway.hashCode() * 47)
@@ -339,7 +394,7 @@
         } else {
             dest.writeByte((byte) 1);
             dest.writeByteArray(mDestination.getAddress().getAddress());
-            dest.writeInt(mDestination.getNetworkPrefixLength());
+            dest.writeInt(mDestination.getPrefixLength());
         }
 
         if (mGateway == null) {
diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java
index bccf556..814ecdd 100644
--- a/core/tests/coretests/src/android/net/LinkAddressTest.java
+++ b/core/tests/coretests/src/android/net/LinkAddressTest.java
@@ -56,26 +56,26 @@
         // Valid addresses work as expected.
         address = new LinkAddress(V4_ADDRESS, 25);
         assertEquals(V4_ADDRESS, address.getAddress());
-        assertEquals(25, address.getNetworkPrefixLength());
+        assertEquals(25, address.getPrefixLength());
         assertEquals(0, address.getFlags());
         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
 
         address = new LinkAddress(V6_ADDRESS, 127);
         assertEquals(V6_ADDRESS, address.getAddress());
-        assertEquals(127, address.getNetworkPrefixLength());
+        assertEquals(127, address.getPrefixLength());
         assertEquals(0, address.getFlags());
         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
 
         // Nonsensical flags/scopes or combinations thereof are acceptable.
         address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
         assertEquals(V6_ADDRESS, address.getAddress());
-        assertEquals(64, address.getNetworkPrefixLength());
+        assertEquals(64, address.getPrefixLength());
         assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
         assertEquals(RT_SCOPE_LINK, address.getScope());
 
         address = new LinkAddress(V4 + "/23", 123, 456);
         assertEquals(V4_ADDRESS, address.getAddress());
-        assertEquals(23, address.getNetworkPrefixLength());
+        assertEquals(23, address.getPrefixLength());
         assertEquals(123, address.getFlags());
         assertEquals(456, address.getScope());
 
@@ -94,10 +94,10 @@
         }
 
         assertEquals(NetworkUtils.numericToInetAddress("127.0.0.1"), ipv4Loopback.getAddress());
-        assertEquals(8, ipv4Loopback.getNetworkPrefixLength());
+        assertEquals(8, ipv4Loopback.getPrefixLength());
 
         assertEquals(NetworkUtils.numericToInetAddress("::1"), ipv6Loopback.getAddress());
-        assertEquals(128, ipv6Loopback.getNetworkPrefixLength());
+        assertEquals(128, ipv6Loopback.getPrefixLength());
 
         // Null addresses are rejected.
         try {
diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java
index 55d6592..01283a6 100644
--- a/core/tests/coretests/src/android/net/RouteInfoTest.java
+++ b/core/tests/coretests/src/android/net/RouteInfoTest.java
@@ -43,17 +43,17 @@
 
         // Invalid input.
         try {
-            r = new RouteInfo(null, null, "rmnet0");
+            r = new RouteInfo((LinkAddress) null, null, "rmnet0");
             fail("Expected RuntimeException:  destination and gateway null");
         } catch(RuntimeException e) {}
 
         // Null destination is default route.
-        r = new RouteInfo(null, Address("2001:db8::1"), null);
+        r = new RouteInfo((LinkAddress) null, Address("2001:db8::1"), null);
         assertEquals(Prefix("::/0"), r.getDestination());
         assertEquals(Address("2001:db8::1"), r.getGateway());
         assertNull(r.getInterface());
 
-        r = new RouteInfo(null, Address("192.0.2.1"), "wlan0");
+        r = new RouteInfo((LinkAddress) null, Address("192.0.2.1"), "wlan0");
         assertEquals(Prefix("0.0.0.0/0"), r.getDestination());
         assertEquals(Address("192.0.2.1"), r.getGateway());
         assertEquals("wlan0", r.getInterface());
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2ece189..657d5ec 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1669,7 +1669,7 @@
                         continue;
                     }
 
-                    int prefix = destination.getNetworkPrefixLength();
+                    int prefix = destination.getPrefixLength();
                     InetAddress addrMasked = NetworkUtils.getNetworkPart(address, prefix);
                     InetAddress destMasked = NetworkUtils.getNetworkPart(destination.getAddress(),
                             prefix);
@@ -1871,7 +1871,7 @@
                             mNetd.addRoute(netId, r);
                         }
                         if (exempt) {
-                            LinkAddress dest = r.getDestination();
+                            LinkAddress dest = r.getDestinationLinkAddress();
                             if (!mExemptAddresses.contains(dest)) {
                                 mNetd.setHostExemption(dest);
                                 mExemptAddresses.add(dest);
@@ -1904,7 +1904,7 @@
                             } else {
                                 mNetd.removeRoute(netId, r);
                             }
-                            LinkAddress dest = r.getDestination();
+                            LinkAddress dest = r.getDestinationLinkAddress();
                             if (mExemptAddresses.contains(dest)) {
                                 mNetd.clearHostExemption(dest);
                                 mExemptAddresses.remove(dest);
@@ -4438,7 +4438,9 @@
                                 mIsProvisioningNetwork.set(true);
                                 MobileDataStateTracker mdst = (MobileDataStateTracker)
                                         mNetTrackers[ConnectivityManager.TYPE_MOBILE];
-                                mdst.setInternalDataEnable(false);
+
+                                // Disable radio until user starts provisioning
+                                mdst.setRadio(false);
                             } else {
                                 if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url");
                             }
@@ -4950,17 +4952,24 @@
         // Mark notification as not visible
         setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null);
 
-        // If provisioning network handle as a special case,
+        // Check airplane mode
+        boolean isAirplaneModeOn = Settings.System.getInt(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+        // If provisioning network and not in airplane mode handle as a special case,
         // otherwise launch browser with the intent directly.
-        if (mIsProvisioningNetwork.get()) {
+        if (mIsProvisioningNetwork.get() && !isAirplaneModeOn) {
             if (DBG) log("handleMobileProvisioningAction: on prov network enable then launch");
+            mIsProvisioningNetwork.set(false);
 //            mIsStartingProvisioning.set(true);
 //            MobileDataStateTracker mdst = (MobileDataStateTracker)
 //                    mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+            // Radio was disabled on CMP_RESULT_CODE_PROVISIONING_NETWORK, enable it here
+//            mdst.setRadio(true);
 //            mdst.setEnableFailFastMobileData(DctConstants.ENABLED);
 //            mdst.enableMobileProvisioning(url);
         } else {
             if (DBG) log("handleMobileProvisioningAction: not prov network");
+            mIsProvisioningNetwork.set(false);
             // Check for  apps that can handle provisioning first
             Intent provisioningIntent = new Intent(TelephonyIntents.ACTION_CARRIER_SETUP);
             provisioningIntent.addCategory(TelephonyIntents.CATEGORY_MCCMNC_PREFIX