Stop using LinkProperties for static configuration.

LinkProperties can represent way more complicated configurations
than what we can actually apply to interfaces. This makes it
error-prone to use it to represent static configuration, both
when trying to apply configuration coming from LinkProperties
and when trying to save configuration from current
LinkProperties.

Instead, move static configuration (IPv4 only, since we don't
support static IPv6 configuration) into a separate
StaticIpConfiguration class.

Bug: 16114392
Bug: 16893413
Change-Id: Ib33f35c004e30b6067bb20235ffa43c247d174df
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 49a307e..71df60a 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -16,13 +16,15 @@
 
 package android.net;
 
+import android.net.NetworkUtils;
 import android.os.Parcelable;
 import android.os.Parcel;
 import android.text.TextUtils;
 import android.util.Log;
 
 import java.net.InetAddress;
-import java.net.UnknownHostException;
+import java.net.Inet4Address;
+import java.util.Objects;
 
 /**
  * A simple object for retrieving the results of a DHCP request.
@@ -30,38 +32,34 @@
  * TODO - remove when DhcpInfo is deprecated.  Move the remaining api to LinkProperties.
  * @hide
  */
-public class DhcpResults implements Parcelable {
+public class DhcpResults extends StaticIpConfiguration {
     private static final String TAG = "DhcpResults";
 
-    public final LinkProperties linkProperties;
-
     public InetAddress serverAddress;
 
-    /**
-     * Vendor specific information (from RFC 2132).
-     */
+    /** Vendor specific information (from RFC 2132). */
     public String vendorInfo;
 
     public int leaseDuration;
 
     public DhcpResults() {
-        linkProperties = new LinkProperties();
+        super();
+    }
+
+    public DhcpResults(StaticIpConfiguration source) {
+        super(source);
     }
 
     /** copy constructor */
     public DhcpResults(DhcpResults source) {
-        if (source != null) {
-            linkProperties = new LinkProperties(source.linkProperties);
-            serverAddress = source.serverAddress;
-            leaseDuration = source.leaseDuration;
-            vendorInfo = source.vendorInfo;
-        } else {
-            linkProperties = new LinkProperties();
-        }
-    }
+        super(source);
 
-    public DhcpResults(LinkProperties lp) {
-        linkProperties = new LinkProperties(lp);
+        if (source != null) {
+            // All these are immutable, so no need to make copies.
+            serverAddress = source.serverAddress;
+            vendorInfo = source.vendorInfo;
+            leaseDuration = source.leaseDuration;
+        }
     }
 
     /**
@@ -70,14 +68,10 @@
      * being empty.
      */
     public void updateFromDhcpRequest(DhcpResults orig) {
-        if (orig == null || orig.linkProperties == null) return;
-        if (linkProperties.getRoutes().size() == 0) {
-            for (RouteInfo r : orig.linkProperties.getRoutes()) linkProperties.addRoute(r);
-        }
-        if (linkProperties.getDnsServers().size() == 0) {
-            for (InetAddress d : orig.linkProperties.getDnsServers()) {
-                linkProperties.addDnsServer(d);
-            }
+        if (orig == null) return;
+        if (gateway == null) gateway = orig.gateway;
+        if (dnsServers.size() == 0) {
+            dnsServers.addAll(orig.dnsServers);
         }
     }
 
@@ -94,15 +88,14 @@
     }
 
     public void clear() {
-        linkProperties.clear();
-        serverAddress = null;
+        super.clear();
         vendorInfo = null;
         leaseDuration = 0;
     }
 
     @Override
     public String toString() {
-        StringBuffer str = new StringBuffer(linkProperties.toString());
+        StringBuffer str = new StringBuffer(super.toString());
 
         str.append(" DHCP server ").append(serverAddress);
         str.append(" Vendor info ").append(vendorInfo);
@@ -119,58 +112,19 @@
 
         DhcpResults target = (DhcpResults)obj;
 
-        if (linkProperties == null) {
-            if (target.linkProperties != null) return false;
-        } else if (!linkProperties.equals(target.linkProperties)) return false;
-        if (serverAddress == null) {
-            if (target.serverAddress != null) return false;
-        } else if (!serverAddress.equals(target.serverAddress)) return false;
-        if (vendorInfo == null) {
-            if (target.vendorInfo != null) return false;
-        } else if (!vendorInfo.equals(target.vendorInfo)) return false;
-        if (leaseDuration != target.leaseDuration) return false;
-
-        return true;
-    }
-
-    /** Implement the Parcelable interface */
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface */
-    public void writeToParcel(Parcel dest, int flags) {
-        linkProperties.writeToParcel(dest, flags);
-
-        dest.writeInt(leaseDuration);
-
-        if (serverAddress != null) {
-            dest.writeByte((byte)1);
-            dest.writeByteArray(serverAddress.getAddress());
-        } else {
-            dest.writeByte((byte)0);
-        }
-
-        dest.writeString(vendorInfo);
+        return super.equals((StaticIpConfiguration) obj) &&
+                Objects.equals(serverAddress, target.serverAddress) &&
+                Objects.equals(vendorInfo, target.vendorInfo) &&
+                leaseDuration == target.leaseDuration;
     }
 
     /** Implement the Parcelable interface */
     public static final Creator<DhcpResults> CREATOR =
         new Creator<DhcpResults>() {
             public DhcpResults createFromParcel(Parcel in) {
-                DhcpResults prop = new DhcpResults((LinkProperties)in.readParcelable(null));
-
-                prop.leaseDuration = in.readInt();
-
-                if (in.readByte() == 1) {
-                    try {
-                        prop.serverAddress = InetAddress.getByAddress(in.createByteArray());
-                    } catch (UnknownHostException e) {}
-                }
-
-                prop.vendorInfo = in.readString();
-
-                return prop;
+                DhcpResults dhcpResults = new DhcpResults();
+                readFromParcel(dhcpResults, in);
+                return dhcpResults;
             }
 
             public DhcpResults[] newArray(int size) {
@@ -178,33 +132,39 @@
             }
         };
 
-    // Utils for jni population - false on success
-    public void setInterfaceName(String interfaceName) {
-        linkProperties.setInterfaceName(interfaceName);
+    /** Implement the Parcelable interface */
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(leaseDuration);
+        NetworkUtils.parcelInetAddress(dest, serverAddress, flags);
+        dest.writeString(vendorInfo);
     }
 
-    public boolean addLinkAddress(String addrString, int prefixLength) {
-        InetAddress addr;
+    private static void readFromParcel(DhcpResults dhcpResults, Parcel in) {
+        StaticIpConfiguration.readFromParcel(dhcpResults, in);
+        dhcpResults.leaseDuration = in.readInt();
+        dhcpResults.serverAddress = NetworkUtils.unparcelInetAddress(in);
+        dhcpResults.vendorInfo = in.readString();
+    }
+
+    // Utils for jni population - false on success
+    // Not part of the superclass because they're only used by the JNI iterface to the DHCP daemon.
+    public boolean setIpAddress(String addrString, int prefixLength) {
         try {
-            addr = NetworkUtils.numericToInetAddress(addrString);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "addLinkAddress failed with addrString " + addrString);
+            Inet4Address addr = (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
+            ipAddress = new LinkAddress(addr, prefixLength);
+        } catch (IllegalArgumentException|ClassCastException e) {
+            Log.e(TAG, "setIpAddress failed with addrString " + addrString + "/" + prefixLength);
             return true;
         }
-
-        LinkAddress linkAddress = new LinkAddress(addr, prefixLength);
-        linkProperties.addLinkAddress(linkAddress);
-
-        RouteInfo routeInfo = new RouteInfo(linkAddress);
-        linkProperties.addRoute(routeInfo);
         return false;
     }
 
-    public boolean addGateway(String addrString) {
+    public boolean setGateway(String addrString) {
         try {
-            linkProperties.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(addrString)));
+            gateway = NetworkUtils.numericToInetAddress(addrString);
         } catch (IllegalArgumentException e) {
-            Log.e(TAG, "addGateway failed with addrString " + addrString);
+            Log.e(TAG, "setGateway failed with addrString " + addrString);
             return true;
         }
         return false;
@@ -213,7 +173,7 @@
     public boolean addDns(String addrString) {
         if (TextUtils.isEmpty(addrString) == false) {
             try {
-                linkProperties.addDnsServer(NetworkUtils.numericToInetAddress(addrString));
+                dnsServers.add(NetworkUtils.numericToInetAddress(addrString));
             } catch (IllegalArgumentException e) {
                 Log.e(TAG, "addDns failed with addrString " + addrString);
                 return true;
@@ -241,6 +201,6 @@
     }
 
     public void setDomains(String domains) {
-        linkProperties.setDomains(domains);
+        domains = domains;
     }
 }
diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
index 608ca28..d965f27 100644
--- a/core/java/android/net/EthernetManager.java
+++ b/core/java/android/net/EthernetManager.java
@@ -21,7 +21,6 @@
 import android.net.IpConfiguration;
 import android.net.IpConfiguration.IpAssignment;
 import android.net.IpConfiguration.ProxySettings;
-import android.net.LinkProperties;
 import android.os.RemoteException;
 
 /**
@@ -52,16 +51,12 @@
      */
     public IpConfiguration getConfiguration() {
         if (mService == null) {
-            return new IpConfiguration(IpAssignment.UNASSIGNED,
-                                       ProxySettings.UNASSIGNED,
-                                       new LinkProperties());
+            return new IpConfiguration();
         }
         try {
             return mService.getConfiguration();
         } catch (RemoteException e) {
-            return new IpConfiguration(IpAssignment.UNASSIGNED,
-                                       ProxySettings.UNASSIGNED,
-                                       new LinkProperties());
+            return new IpConfiguration();
         }
     }
 
diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java
index 4730bab..fe69f296 100644
--- a/core/java/android/net/IpConfiguration.java
+++ b/core/java/android/net/IpConfiguration.java
@@ -16,7 +16,7 @@
 
 package android.net;
 
-import android.net.LinkProperties;
+import android.net.StaticIpConfiguration;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -31,7 +31,7 @@
 
     public enum IpAssignment {
         /* Use statically configured IP settings. Configuration can be accessed
-         * with linkProperties */
+         * with staticIpConfiguration */
         STATIC,
         /* Use dynamically configured IP settigns */
         DHCP,
@@ -42,12 +42,14 @@
 
     public IpAssignment ipAssignment;
 
+    public StaticIpConfiguration staticIpConfiguration;
+
     public enum ProxySettings {
         /* No proxy is to be used. Any existing proxy settings
          * should be cleared. */
         NONE,
         /* Use statically configured proxy. Configuration can be accessed
-         * with linkProperties */
+         * with httpProxy. */
         STATIC,
         /* no proxy details are assigned, this is used to indicate
          * that any existing proxy settings should be retained */
@@ -59,30 +61,69 @@
 
     public ProxySettings proxySettings;
 
-    public LinkProperties linkProperties;
+    public ProxyInfo httpProxy;
 
-    public IpConfiguration(IpConfiguration source) {
-        if (source != null) {
-            ipAssignment = source.ipAssignment;
-            proxySettings = source.proxySettings;
-            linkProperties = new LinkProperties(source.linkProperties);
-        } else {
-            ipAssignment = IpAssignment.UNASSIGNED;
-            proxySettings = ProxySettings.UNASSIGNED;
-            linkProperties = new LinkProperties();
-        }
+    private void init(IpAssignment ipAssignment,
+                      ProxySettings proxySettings,
+                      StaticIpConfiguration staticIpConfiguration,
+                      ProxyInfo httpProxy) {
+        this.ipAssignment = ipAssignment;
+        this.proxySettings = proxySettings;
+        this.staticIpConfiguration = (staticIpConfiguration == null) ?
+                null : new StaticIpConfiguration(staticIpConfiguration);
+        this.httpProxy = (httpProxy == null) ?
+                null : new ProxyInfo(httpProxy);
     }
 
     public IpConfiguration() {
-         this(null);
+        init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null);
     }
 
     public IpConfiguration(IpAssignment ipAssignment,
                            ProxySettings proxySettings,
-                           LinkProperties linkProperties) {
+                           StaticIpConfiguration staticIpConfiguration,
+                           ProxyInfo httpProxy) {
+        init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy);
+    }
+
+    public IpConfiguration(IpConfiguration source) {
+        this();
+        if (source != null) {
+            init(source.ipAssignment, source.proxySettings,
+                 source.staticIpConfiguration, source.httpProxy);
+        }
+    }
+
+    public IpAssignment getIpAssignment() {
+        return ipAssignment;
+    }
+
+    public void setIpAssignment(IpAssignment ipAssignment) {
         this.ipAssignment = ipAssignment;
+    }
+
+    public StaticIpConfiguration getStaticIpConfiguration() {
+        return staticIpConfiguration;
+    }
+
+    public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) {
+        this.staticIpConfiguration = staticIpConfiguration;
+    }
+
+    public ProxySettings getProxySettings() {
+        return proxySettings;
+    }
+
+    public void setProxySettings(ProxySettings proxySettings) {
         this.proxySettings = proxySettings;
-        this.linkProperties = new LinkProperties(linkProperties);
+    }
+
+    public ProxyInfo getHttpProxy() {
+        return httpProxy;
+    }
+
+    public void setHttpProxy(ProxyInfo httpProxy) {
+        this.httpProxy = httpProxy;
     }
 
     @Override
@@ -90,10 +131,16 @@
         StringBuilder sbuf = new StringBuilder();
         sbuf.append("IP assignment: " + ipAssignment.toString());
         sbuf.append("\n");
+        if (staticIpConfiguration != null) {
+            sbuf.append("Static configuration: " + staticIpConfiguration.toString());
+            sbuf.append("\n");
+        }
         sbuf.append("Proxy settings: " + proxySettings.toString());
         sbuf.append("\n");
-        sbuf.append(linkProperties.toString());
-        sbuf.append("\n");
+        if (httpProxy != null) {
+            sbuf.append("HTTP proxy: " + httpProxy.toString());
+            sbuf.append("\n");
+        }
 
         return sbuf.toString();
     }
@@ -111,14 +158,16 @@
         IpConfiguration other = (IpConfiguration) o;
         return this.ipAssignment == other.ipAssignment &&
                 this.proxySettings == other.proxySettings &&
-                Objects.equals(this.linkProperties, other.linkProperties);
+                Objects.equals(this.staticIpConfiguration, other.staticIpConfiguration) &&
+                Objects.equals(this.httpProxy, other.httpProxy);
     }
 
     @Override
     public int hashCode() {
-        return 13 + (linkProperties != null ? linkProperties.hashCode() : 0) +
+        return 13 + (staticIpConfiguration != null ? staticIpConfiguration.hashCode() : 0) +
                17 * ipAssignment.ordinal() +
-               47 * proxySettings.ordinal();
+               47 * proxySettings.ordinal() +
+               83 * httpProxy.hashCode();
     }
 
     /** Implement the Parcelable interface */
@@ -130,7 +179,8 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(ipAssignment.name());
         dest.writeString(proxySettings.name());
-        dest.writeParcelable(linkProperties, flags);
+        dest.writeParcelable(staticIpConfiguration, flags);
+        dest.writeParcelable(httpProxy, flags);
     }
 
     /** Implement the Parcelable interface */
@@ -140,7 +190,8 @@
                 IpConfiguration config = new IpConfiguration();
                 config.ipAssignment = IpAssignment.valueOf(in.readString());
                 config.proxySettings = ProxySettings.valueOf(in.readString());
-                config.linkProperties = in.readParcelable(null);
+                config.staticIpConfiguration = in.readParcelable(null);
+                config.httpProxy = in.readParcelable(null);
                 return config;
             }
 
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 663aa15..54d8676 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -23,6 +23,7 @@
 import java.util.Collection;
 import java.util.Locale;
 
+import android.os.Parcel;
 import android.util.Log;
 import android.util.Pair;
 
@@ -203,6 +204,32 @@
     }
 
     /**
+     * Writes an InetAddress to a parcel. The address may be null. This is likely faster than
+     * calling writeSerializable.
+     */
+    protected static void parcelInetAddress(Parcel parcel, InetAddress address, int flags) {
+        byte[] addressArray = (address != null) ? address.getAddress() : null;
+        parcel.writeByteArray(addressArray);
+    }
+
+    /**
+     * Reads an InetAddress from a parcel. Returns null if the address that was written was null
+     * or if the data is invalid.
+     */
+    protected static InetAddress unparcelInetAddress(Parcel in) {
+        byte[] addressArray = in.createByteArray();
+        if (addressArray == null) {
+            return null;
+        }
+        try {
+            return InetAddress.getByAddress(addressArray);
+        } catch (UnknownHostException e) {
+            return null;
+        }
+    }
+
+
+    /**
      *  Masks a raw IP address byte array with the specified prefix length.
      */
     public static void maskRawAddress(byte[] array, int prefixLength) {
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
new file mode 100644
index 0000000..5a273cf
--- /dev/null
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -0,0 +1,194 @@
+/*
+ * 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.net.LinkAddress;
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Class that describes static IP configuration.
+ *
+ * This class is different from LinkProperties because it represents
+ * configuration intent. The general contract is that if we can represent
+ * a configuration here, then we should be able to configure it on a network.
+ * The intent is that it closely match the UI we have for configuring networks.
+ *
+ * In contrast, LinkProperties represents current state. It is much more
+ * expressive. For example, it supports multiple IP addresses, multiple routes,
+ * stacked interfaces, and so on. Because LinkProperties is so expressive,
+ * using it to represent configuration intent as well as current state causes
+ * problems. For example, we could unknowingly save a configuration that we are
+ * not in fact capable of applying, or we could save a configuration that the
+ * UI cannot display, which has the potential for malicious code to hide
+ * hostile or unexpected configuration from the user: see, for example,
+ * http://b/12663469 and http://b/16893413 .
+ *
+ * @hide
+ */
+public class StaticIpConfiguration implements Parcelable {
+    public LinkAddress ipAddress;
+    public InetAddress gateway;
+    public final ArrayList<InetAddress> dnsServers;
+    public String domains;
+
+    public StaticIpConfiguration() {
+        dnsServers = new ArrayList<InetAddress>();
+    }
+
+    public StaticIpConfiguration(StaticIpConfiguration source) {
+        this();
+        if (source != null) {
+            // All of these except dnsServers are immutable, so no need to make copies.
+            ipAddress = source.ipAddress;
+            gateway = source.gateway;
+            dnsServers.addAll(source.dnsServers);
+            domains = source.domains;
+        }
+    }
+
+    public void clear() {
+        ipAddress = null;
+        gateway = null;
+        dnsServers.clear();
+        domains = null;
+    }
+
+    /**
+     * Returns the network routes specified by this object. Will typically include a
+     * directly-connected route for the IP address's local subnet and a default route.
+     */
+    public List<RouteInfo> getRoutes(String iface) {
+        List<RouteInfo> routes = new ArrayList<RouteInfo>(2);
+        if (ipAddress != null) {
+            routes.add(new RouteInfo(ipAddress, null, iface));
+        }
+        if (gateway != null) {
+            routes.add(new RouteInfo((LinkAddress) null, gateway, iface));
+        }
+        return routes;
+    }
+
+    /**
+     * Returns a LinkProperties object expressing the data in this object. Note that the information
+     * contained in the LinkProperties will not be a complete picture of the link's configuration,
+     * because any configuration information that is obtained dynamically by the network (e.g.,
+     * IPv6 configuration) will not be included.
+     */
+    public LinkProperties toLinkProperties(String iface) {
+        LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(iface);
+        if (ipAddress != null) {
+            lp.addLinkAddress(ipAddress);
+        }
+        for (RouteInfo route : getRoutes(iface)) {
+            lp.addRoute(route);
+        }
+        for (InetAddress dns : dnsServers) {
+            lp.addDnsServer(dns);
+        }
+        return lp;
+    }
+
+    public String toString() {
+        StringBuffer str = new StringBuffer();
+
+        str.append("IP address ");
+        if (ipAddress != null ) str.append(ipAddress).append(" ");
+
+        str.append("Gateway ");
+        if (gateway != null) str.append(gateway.getHostAddress()).append(" ");
+
+        str.append(" DNS servers: [");
+        for (InetAddress dnsServer : dnsServers) {
+            str.append(" ").append(dnsServer.getHostAddress());
+        }
+
+        str.append(" ] Domains");
+        if (domains != null) str.append(domains);
+        return str.toString();
+    }
+
+    public int hashCode() {
+        int result = 13;
+        result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode());
+        result = 47 * result + (gateway == null ? 0 : gateway.hashCode());
+        result = 47 * result + (domains == null ? 0 : domains.hashCode());
+        result = 47 * result + dnsServers.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+
+        if (!(obj instanceof StaticIpConfiguration)) return false;
+
+        StaticIpConfiguration other = (StaticIpConfiguration) obj;
+
+        return other != null &&
+                Objects.equals(ipAddress, other.ipAddress) &&
+                Objects.equals(gateway, other.gateway) &&
+                dnsServers.equals(other.dnsServers) &&
+                Objects.equals(domains, other.domains);
+    }
+
+    /** Implement the Parcelable interface */
+    public static Creator<StaticIpConfiguration> CREATOR =
+        new Creator<StaticIpConfiguration>() {
+            public StaticIpConfiguration createFromParcel(Parcel in) {
+                StaticIpConfiguration s = new StaticIpConfiguration();
+                readFromParcel(s, in);
+                return s;
+            }
+
+            public StaticIpConfiguration[] newArray(int size) {
+                return new StaticIpConfiguration[size];
+            }
+        };
+
+    /** Implement the Parcelable interface */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(ipAddress, flags);
+        NetworkUtils.parcelInetAddress(dest, gateway, flags);
+        dest.writeInt(dnsServers.size());
+        for (InetAddress dnsServer : dnsServers) {
+            NetworkUtils.parcelInetAddress(dest, dnsServer, flags);
+        }
+    }
+
+    protected static void readFromParcel(StaticIpConfiguration s, Parcel in) {
+        s.ipAddress = in.readParcelable(null);
+        s.gateway = NetworkUtils.unparcelInetAddress(in);
+        s.dnsServers.clear();
+        int size = in.readInt();
+        for (int i = 0; i < size; i++) {
+            s.dnsServers.add(NetworkUtils.unparcelInetAddress(in));
+        }
+    }
+}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 32cf286..5bd38f3 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -69,9 +69,8 @@
  */
 static struct fieldIds {
     jmethodID clear;
-    jmethodID setInterfaceName;
-    jmethodID addLinkAddress;
-    jmethodID addGateway;
+    jmethodID setIpAddress;
+    jmethodID setGateway;
     jmethodID addDns;
     jmethodID setDomains;
     jmethodID setServerAddress;
@@ -130,21 +129,16 @@
     if (result == 0) {
         env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear);
 
-        // set mIfaceName
-        // dhcpResults->setInterfaceName(ifname)
-        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setInterfaceName, ifname);
-
         // set the linkAddress
         // dhcpResults->addLinkAddress(inetAddress, prefixLength)
-        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.addLinkAddress,
+        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setIpAddress,
                 env->NewStringUTF(ipaddr), prefixLength);
     }
 
     if (result == 0) {
         // set the gateway
-        // dhcpResults->addGateway(gateway)
         result = env->CallBooleanMethod(dhcpResults,
-                dhcpResultsFieldIds.addGateway, env->NewStringUTF(gateway));
+                dhcpResultsFieldIds.setGateway, env->NewStringUTF(gateway));
     }
 
     if (result == 0) {
@@ -279,12 +273,10 @@
     LOG_FATAL_IF(dhcpResultsClass == NULL, "Unable to find class android/net/DhcpResults");
     dhcpResultsFieldIds.clear =
             env->GetMethodID(dhcpResultsClass, "clear", "()V");
-    dhcpResultsFieldIds.setInterfaceName =
-            env->GetMethodID(dhcpResultsClass, "setInterfaceName", "(Ljava/lang/String;)V");
-    dhcpResultsFieldIds.addLinkAddress =
-            env->GetMethodID(dhcpResultsClass, "addLinkAddress", "(Ljava/lang/String;I)Z");
-    dhcpResultsFieldIds.addGateway =
-            env->GetMethodID(dhcpResultsClass, "addGateway", "(Ljava/lang/String;)Z");
+    dhcpResultsFieldIds.setIpAddress =
+            env->GetMethodID(dhcpResultsClass, "setIpAddress", "(Ljava/lang/String;I)Z");
+    dhcpResultsFieldIds.setGateway =
+            env->GetMethodID(dhcpResultsClass, "setGateway", "(Ljava/lang/String;)Z");
     dhcpResultsFieldIds.addDns =
             env->GetMethodID(dhcpResultsClass, "addDns", "(Ljava/lang/String;)Z");
     dhcpResultsFieldIds.setDomains =
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 116a31e..93b16e7 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -26,8 +26,8 @@
 import android.net.IpConfiguration.IpAssignment;
 import android.net.IpConfiguration.ProxySettings;
 import android.net.LinkAddress;
-import android.net.LinkProperties;
 import android.net.RouteInfo;
+import android.net.StaticIpConfiguration;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -116,7 +116,7 @@
         boolean usercert = false;
         WifiConfiguration config = null;
         int securityType = NONE;
-        LinkProperties mLinkProperties = null;
+        StaticIpConfiguration mStaticIpConfiguration = null;
         InetAddress mInetAddr = null;
 
         @Override
@@ -153,7 +153,7 @@
                 usercert = true;
             }
             if (tagName.equalsIgnoreCase("ip")) {
-                mLinkProperties = new LinkProperties();
+                mStaticIpConfiguration = new StaticIpConfiguration();
                 ip = true;
             }
             if (tagName.equalsIgnoreCase("gateway")) {
@@ -173,15 +173,15 @@
         @Override
         public void endElement(String uri, String localName, String tagName) throws SAXException {
             if (tagName.equalsIgnoreCase("accesspoint")) {
-                if (mLinkProperties != null) {
+                if (mStaticIpConfiguration != null) {
                     config.setIpAssignment(IpAssignment.STATIC);
-                    config.setLinkProperties(mLinkProperties);
+                    config.setStaticIpConfiguration(mStaticIpConfiguration);
                 } else {
                     config.setIpAssignment(IpAssignment.DHCP);
                 }
                 config.setProxySettings(ProxySettings.NONE);
                 networks.add(config);
-                mLinkProperties = null;
+                mStaticIpConfiguration = null;
             }
         }
 
@@ -312,7 +312,7 @@
                     if (!InetAddress.isNumeric(gwAddr)) {
                         throw new SAXException();
                     }
-                    mLinkProperties.addRoute(new RouteInfo(InetAddress.getByName(gwAddr)));
+                    mStaticIpConfiguration.gateway = InetAddress.getByName(gwAddr);
                 } catch (UnknownHostException e) {
                     throw new SAXException();
                 }
@@ -324,7 +324,7 @@
                     if ((nwPrefixLength < 0) || (nwPrefixLength > 32)) {
                         throw new SAXException();
                     }
-                    mLinkProperties.addLinkAddress(new LinkAddress(mInetAddr, nwPrefixLength));
+                    mStaticIpConfiguration.ipAddress = new LinkAddress(mInetAddr, nwPrefixLength);
                 } catch (NumberFormatException e) {
                     throw new SAXException();
                 }
@@ -336,7 +336,7 @@
                     if (!InetAddress.isNumeric(dnsAddr)) {
                         throw new SAXException();
                     }
-                    mLinkProperties.addDnsServer(InetAddress.getByName(dnsAddr));
+                    mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(dnsAddr));
                 } catch (UnknownHostException e) {
                     throw new SAXException();
                 }
@@ -348,7 +348,7 @@
                     if (!InetAddress.isNumeric(dnsAddr)) {
                         throw new SAXException();
                     }
-                    mLinkProperties.addDnsServer(InetAddress.getByName(dnsAddr));
+                    mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(dnsAddr));
                 } catch (UnknownHostException e) {
                     throw new SAXException();
                 }