Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net.wifi;
     18 
     19 import android.net.LinkProperties;
     20 import android.os.Parcelable;
     21 import android.os.Parcel;
     22 import android.text.TextUtils;
     23 
     24 import java.util.BitSet;
     25 
     26 /**
     27  * A class representing a configured Wi-Fi network, including the
     28  * security configuration.
     29  */
     30 public class WifiConfiguration implements Parcelable {
     31     private static final String TAG = "WifiConfiguration";
     32     /** {@hide} */
     33     public static final String ssidVarName = "ssid";
     34     /** {@hide} */
     35     public static final String bssidVarName = "bssid";
     36     /** {@hide} */
     37     public static final String pskVarName = "psk";
     38     /** {@hide} */
     39     public static final String[] wepKeyVarNames = { "wep_key0", "wep_key1", "wep_key2", "wep_key3" };
     40     /** {@hide} */
     41     public static final String wepTxKeyIdxVarName = "wep_tx_keyidx";
     42     /** {@hide} */
     43     public static final String priorityVarName = "priority";
     44     /** {@hide} */
     45     public static final String hiddenSSIDVarName = "scan_ssid";
     46     /** {@hide} */
     47     public static final int INVALID_NETWORK_ID = -1;
     48     /**
     49      * Recognized key management schemes.
     50      */
     51     public static class KeyMgmt {
     52         private KeyMgmt() { }
     53 
     54         /** WPA is not used; plaintext or static WEP could be used. */
     55         public static final int NONE = 0;
     56         /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */
     57         public static final int WPA_PSK = 1;
     58         /** WPA using EAP authentication. Generally used with an external authentication server. */
     59         public static final int WPA_EAP = 2;
     60         /** IEEE 802.1X using EAP authentication and (optionally) dynamically
     61          * generated WEP keys. */
     62         public static final int IEEE8021X = 3;
     63 
     64         /** WPA2 pre-shared key for use with soft access point
     65           * (requires {@code preSharedKey} to be specified).
     66           * @hide
     67           */
     68         public static final int WPA2_PSK = 4;
     69 
     70         public static final String varName = "key_mgmt";
     71 
     72         public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X",
     73                 "WPA2_PSK" };
     74     }
     75 
     76     /**
     77      * Recognized security protocols.
     78      */
     79     public static class Protocol {
     80         private Protocol() { }
     81 
     82         /** WPA/IEEE 802.11i/D3.0 */
     83         public static final int WPA = 0;
     84         /** WPA2/IEEE 802.11i */
     85         public static final int RSN = 1;
     86 
     87         public static final String varName = "proto";
     88 
     89         public static final String[] strings = { "WPA", "RSN" };
     90     }
     91 
     92     /**
     93      * Recognized IEEE 802.11 authentication algorithms.
     94      */
     95     public static class AuthAlgorithm {
     96         private AuthAlgorithm() { }
     97 
     98         /** Open System authentication (required for WPA/WPA2) */
     99         public static final int OPEN = 0;
    100         /** Shared Key authentication (requires static WEP keys) */
    101         public static final int SHARED = 1;
    102         /** LEAP/Network EAP (only used with LEAP) */
    103         public static final int LEAP = 2;
    104 
    105         public static final String varName = "auth_alg";
    106 
    107         public static final String[] strings = { "OPEN", "SHARED", "LEAP" };
    108     }
    109 
    110     /**
    111      * Recognized pairwise ciphers for WPA.
    112      */
    113     public static class PairwiseCipher {
    114         private PairwiseCipher() { }
    115 
    116         /** Use only Group keys (deprecated) */
    117         public static final int NONE = 0;
    118         /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */
    119         public static final int TKIP = 1;
    120         /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
    121         public static final int CCMP = 2;
    122 
    123         public static final String varName = "pairwise";
    124 
    125         public static final String[] strings = { "NONE", "TKIP", "CCMP" };
    126     }
    127 
    128     /**
    129      * Recognized group ciphers.
    130      * <pre>
    131      * CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
    132      * TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
    133      * WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
    134      * WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11)
    135      * </pre>
    136      */
    137     public static class GroupCipher {
    138         private GroupCipher() { }
    139 
    140         /** WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11) */
    141         public static final int WEP40 = 0;
    142         /** WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key */
    143         public static final int WEP104 = 1;
    144         /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */
    145         public static final int TKIP = 2;
    146         /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
    147         public static final int CCMP = 3;
    148 
    149         public static final String varName = "group";
    150 
    151         public static final String[] strings = { "WEP40", "WEP104", "TKIP", "CCMP" };
    152     }
    153 
    154     /** Possible status of a network configuration. */
    155     public static class Status {
    156         private Status() { }
    157 
    158         /** this is the network we are currently connected to */
    159         public static final int CURRENT = 0;
    160         /** supplicant will not attempt to use this network */
    161         public static final int DISABLED = 1;
    162         /** supplicant will consider this network available for association */
    163         public static final int ENABLED = 2;
    164 
    165         public static final String[] strings = { "current", "disabled", "enabled" };
    166     }
    167 
    168     /** @hide */
    169     public static final int DISABLED_UNKNOWN_REASON                         = 0;
    170     /** @hide */
    171     public static final int DISABLED_DNS_FAILURE                            = 1;
    172     /** @hide */
    173     public static final int DISABLED_DHCP_FAILURE                           = 2;
    174     /** @hide */
    175     public static final int DISABLED_AUTH_FAILURE                           = 3;
    176 
    177     /**
    178      * The ID number that the supplicant uses to identify this
    179      * network configuration entry. This must be passed as an argument
    180      * to most calls into the supplicant.
    181      */
    182     public int networkId;
    183 
    184     /**
    185      * The current status of this network configuration entry.
    186      * @see Status
    187      */
    188     public int status;
    189 
    190     /**
    191      * The code referring to a reason for disabling the network
    192      * Valid when {@link #status} == Status.DISABLED
    193      * @hide
    194      */
    195     public int disableReason;
    196 
    197     /**
    198      * The network's SSID. Can either be an ASCII string,
    199      * which must be enclosed in double quotation marks
    200      * (e.g., {@code "MyNetwork"}, or a string of
    201      * hex digits,which are not enclosed in quotes
    202      * (e.g., {@code 01a243f405}).
    203      */
    204     public String SSID;
    205     /**
    206      * When set, this network configuration entry should only be used when
    207      * associating with the AP having the specified BSSID. The value is
    208      * a string in the format of an Ethernet MAC address, e.g.,
    209      * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit.
    210      */
    211     public String BSSID;
    212 
    213     /**
    214      * Pre-shared key for use with WPA-PSK.
    215      * <p/>
    216      * When the value of this key is read, the actual key is
    217      * not returned, just a "*" if the key has a value, or the null
    218      * string otherwise.
    219      */
    220     public String preSharedKey;
    221     /**
    222      * Up to four WEP keys. Either an ASCII string enclosed in double
    223      * quotation marks (e.g., {@code "abcdef"} or a string
    224      * of hex digits (e.g., {@code 0102030405}).
    225      * <p/>
    226      * When the value of one of these keys is read, the actual key is
    227      * not returned, just a "*" if the key has a value, or the null
    228      * string otherwise.
    229      */
    230     public String[] wepKeys;
    231 
    232     /** Default WEP key index, ranging from 0 to 3. */
    233     public int wepTxKeyIndex;
    234 
    235     /**
    236      * Priority determines the preference given to a network by {@code wpa_supplicant}
    237      * when choosing an access point with which to associate.
    238      */
    239     public int priority;
    240 
    241     /**
    242      * This is a network that does not broadcast its SSID, so an
    243      * SSID-specific probe request must be used for scans.
    244      */
    245     public boolean hiddenSSID;
    246 
    247     /**
    248      * The set of key management protocols supported by this configuration.
    249      * See {@link KeyMgmt} for descriptions of the values.
    250      * Defaults to WPA-PSK WPA-EAP.
    251      */
    252     public BitSet allowedKeyManagement;
    253     /**
    254      * The set of security protocols supported by this configuration.
    255      * See {@link Protocol} for descriptions of the values.
    256      * Defaults to WPA RSN.
    257      */
    258     public BitSet allowedProtocols;
    259     /**
    260      * The set of authentication protocols supported by this configuration.
    261      * See {@link AuthAlgorithm} for descriptions of the values.
    262      * Defaults to automatic selection.
    263      */
    264     public BitSet allowedAuthAlgorithms;
    265     /**
    266      * The set of pairwise ciphers for WPA supported by this configuration.
    267      * See {@link PairwiseCipher} for descriptions of the values.
    268      * Defaults to CCMP TKIP.
    269      */
    270     public BitSet allowedPairwiseCiphers;
    271     /**
    272      * The set of group ciphers supported by this configuration.
    273      * See {@link GroupCipher} for descriptions of the values.
    274      * Defaults to CCMP TKIP WEP104 WEP40.
    275      */
    276     public BitSet allowedGroupCiphers;
    277     /**
    278      * The enterprise configuration details specifying the EAP method,
    279      * certificates and other settings associated with the EAP.
    280      */
    281     public WifiEnterpriseConfig enterpriseConfig;
    282 
    283     /**
    284      * @hide
    285      */
    286     public enum IpAssignment {
    287         /* Use statically configured IP settings. Configuration can be accessed
    288          * with linkProperties */
    289         STATIC,
    290         /* Use dynamically configured IP settigns */
    291         DHCP,
    292         /* no IP details are assigned, this is used to indicate
    293          * that any existing IP settings should be retained */
    294         UNASSIGNED
    295     }
    296     /**
    297      * @hide
    298      */
    299     public IpAssignment ipAssignment;
    300 
    301     /**
    302      * @hide
    303      */
    304     public enum ProxySettings {
    305         /* No proxy is to be used. Any existing proxy settings
    306          * should be cleared. */
    307         NONE,
    308         /* Use statically configured proxy. Configuration can be accessed
    309          * with linkProperties */
    310         STATIC,
    311         /* no proxy details are assigned, this is used to indicate
    312          * that any existing proxy settings should be retained */
    313         UNASSIGNED
    314     }
    315     /**
    316      * @hide
    317      */
    318     public ProxySettings proxySettings;
    319     /**
    320      * @hide
    321      */
    322     public LinkProperties linkProperties;
    323 
    324     public WifiConfiguration() {
    325         networkId = INVALID_NETWORK_ID;
    326         SSID = null;
    327         BSSID = null;
    328         priority = 0;
    329         hiddenSSID = false;
    330         disableReason = DISABLED_UNKNOWN_REASON;
    331         allowedKeyManagement = new BitSet();
    332         allowedProtocols = new BitSet();
    333         allowedAuthAlgorithms = new BitSet();
    334         allowedPairwiseCiphers = new BitSet();
    335         allowedGroupCiphers = new BitSet();
    336         wepKeys = new String[4];
    337         for (int i = 0; i < wepKeys.length; i++) {
    338             wepKeys[i] = null;
    339         }
    340         enterpriseConfig = new WifiEnterpriseConfig();
    341         ipAssignment = IpAssignment.UNASSIGNED;
    342         proxySettings = ProxySettings.UNASSIGNED;
    343         linkProperties = new LinkProperties();
    344     }
    345 
    346     @Override
    347     public String toString() {
    348         StringBuilder sbuf = new StringBuilder();
    349         if (this.status == WifiConfiguration.Status.CURRENT) {
    350             sbuf.append("* ");
    351         } else if (this.status == WifiConfiguration.Status.DISABLED) {
    352             sbuf.append("- DSBLE: ").append(this.disableReason).append(" ");
    353         }
    354         sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
    355                 append(" BSSID: ").append(this.BSSID).append(" PRIO: ").append(this.priority).
    356                 append('\n');
    357         sbuf.append(" KeyMgmt:");
    358         for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
    359             if (this.allowedKeyManagement.get(k)) {
    360                 sbuf.append(" ");
    361                 if (k < KeyMgmt.strings.length) {
    362                     sbuf.append(KeyMgmt.strings[k]);
    363                 } else {
    364                     sbuf.append("??");
    365                 }
    366             }
    367         }
    368         sbuf.append(" Protocols:");
    369         for (int p = 0; p < this.allowedProtocols.size(); p++) {
    370             if (this.allowedProtocols.get(p)) {
    371                 sbuf.append(" ");
    372                 if (p < Protocol.strings.length) {
    373                     sbuf.append(Protocol.strings[p]);
    374                 } else {
    375                     sbuf.append("??");
    376                 }
    377             }
    378         }
    379         sbuf.append('\n');
    380         sbuf.append(" AuthAlgorithms:");
    381         for (int a = 0; a < this.allowedAuthAlgorithms.size(); a++) {
    382             if (this.allowedAuthAlgorithms.get(a)) {
    383                 sbuf.append(" ");
    384                 if (a < AuthAlgorithm.strings.length) {
    385                     sbuf.append(AuthAlgorithm.strings[a]);
    386                 } else {
    387                     sbuf.append("??");
    388                 }
    389             }
    390         }
    391         sbuf.append('\n');
    392         sbuf.append(" PairwiseCiphers:");
    393         for (int pc = 0; pc < this.allowedPairwiseCiphers.size(); pc++) {
    394             if (this.allowedPairwiseCiphers.get(pc)) {
    395                 sbuf.append(" ");
    396                 if (pc < PairwiseCipher.strings.length) {
    397                     sbuf.append(PairwiseCipher.strings[pc]);
    398                 } else {
    399                     sbuf.append("??");
    400                 }
    401             }
    402         }
    403         sbuf.append('\n');
    404         sbuf.append(" GroupCiphers:");
    405         for (int gc = 0; gc < this.allowedGroupCiphers.size(); gc++) {
    406             if (this.allowedGroupCiphers.get(gc)) {
    407                 sbuf.append(" ");
    408                 if (gc < GroupCipher.strings.length) {
    409                     sbuf.append(GroupCipher.strings[gc]);
    410                 } else {
    411                     sbuf.append("??");
    412                 }
    413             }
    414         }
    415         sbuf.append('\n').append(" PSK: ");
    416         if (this.preSharedKey != null) {
    417             sbuf.append('*');
    418         }
    419 
    420         sbuf.append(enterpriseConfig);
    421         sbuf.append('\n');
    422 
    423         sbuf.append("IP assignment: " + ipAssignment.toString());
    424         sbuf.append("\n");
    425         sbuf.append("Proxy settings: " + proxySettings.toString());
    426         sbuf.append("\n");
    427         sbuf.append(linkProperties.toString());
    428         sbuf.append("\n");
    429 
    430         return sbuf.toString();
    431     }
    432 
    433     /**
    434      * Construct a WifiConfiguration from a scanned network
    435      * @param scannedAP the scan result used to construct the config entry
    436      * TODO: figure out whether this is a useful way to construct a new entry.
    437      *
    438     public WifiConfiguration(ScanResult scannedAP) {
    439         networkId = -1;
    440         SSID = scannedAP.SSID;
    441         BSSID = scannedAP.BSSID;
    442     }
    443     */
    444 
    445     /** {@hide} */
    446     public String getPrintableSsid() {
    447         if (SSID == null) return "";
    448         final int length = SSID.length();
    449         if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') {
    450             return SSID.substring(1, length - 1);
    451         }
    452 
    453         /** The ascii-encoded string format is P"<ascii-encoded-string>"
    454          * The decoding is implemented in the supplicant for a newly configured
    455          * network.
    456          */
    457         if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') &&
    458                 (SSID.charAt(length-1) == '"')) {
    459             WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(
    460                     SSID.substring(2, length - 1));
    461             return wifiSsid.toString();
    462         }
    463         return SSID;
    464     }
    465 
    466     /**
    467      * Get an identifier for associating credentials with this config
    468      * @param current configuration contains values for additional fields
    469      *                that are not part of this configuration. Used
    470      *                when a config with some fields is passed by an application.
    471      * @throws IllegalStateException if config is invalid for key id generation
    472      * @hide
    473      */
    474     String getKeyIdForCredentials(WifiConfiguration current) {
    475         String keyMgmt = null;
    476 
    477         try {
    478             // Get current config details for fields that are not initialized
    479             if (TextUtils.isEmpty(SSID)) SSID = current.SSID;
    480             if (allowedKeyManagement.cardinality() == 0) {
    481                 allowedKeyManagement = current.allowedKeyManagement;
    482             }
    483             if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
    484                 keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP];
    485             }
    486             if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
    487                 keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X];
    488             }
    489 
    490             if (TextUtils.isEmpty(keyMgmt)) {
    491                 throw new IllegalStateException("Not an EAP network");
    492             }
    493 
    494             return trimStringForKeyId(SSID) + "_" + keyMgmt + "_" +
    495                     trimStringForKeyId(enterpriseConfig.getKeyId(current != null ?
    496                             current.enterpriseConfig : null));
    497         } catch (NullPointerException e) {
    498             throw new IllegalStateException("Invalid config details");
    499         }
    500     }
    501 
    502     private String trimStringForKeyId(String string) {
    503         // Remove quotes and spaces
    504         return string.replace("\"", "").replace(" ", "");
    505     }
    506 
    507     private static BitSet readBitSet(Parcel src) {
    508         int cardinality = src.readInt();
    509 
    510         BitSet set = new BitSet();
    511         for (int i = 0; i < cardinality; i++) {
    512             set.set(src.readInt());
    513         }
    514 
    515         return set;
    516     }
    517 
    518     private static void writeBitSet(Parcel dest, BitSet set) {
    519         int nextSetBit = -1;
    520 
    521         dest.writeInt(set.cardinality());
    522 
    523         while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
    524             dest.writeInt(nextSetBit);
    525         }
    526     }
    527 
    528     /** @hide */
    529     public int getAuthType() {
    530         if (allowedKeyManagement.cardinality() > 1) {
    531             throw new IllegalStateException("More than one auth type set");
    532         }
    533         if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
    534             return KeyMgmt.WPA_PSK;
    535         } else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
    536             return KeyMgmt.WPA2_PSK;
    537         } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
    538             return KeyMgmt.WPA_EAP;
    539         } else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
    540             return KeyMgmt.IEEE8021X;
    541         }
    542         return KeyMgmt.NONE;
    543     }
    544 
    545     /** Implement the Parcelable interface {@hide} */
    546     public int describeContents() {
    547         return 0;
    548     }
    549 
    550     /** copy constructor {@hide} */
    551     public WifiConfiguration(WifiConfiguration source) {
    552         if (source != null) {
    553             networkId = source.networkId;
    554             status = source.status;
    555             disableReason = source.disableReason;
    556             SSID = source.SSID;
    557             BSSID = source.BSSID;
    558             preSharedKey = source.preSharedKey;
    559 
    560             wepKeys = new String[4];
    561             for (int i = 0; i < wepKeys.length; i++) {
    562                 wepKeys[i] = source.wepKeys[i];
    563             }
    564 
    565             wepTxKeyIndex = source.wepTxKeyIndex;
    566             priority = source.priority;
    567             hiddenSSID = source.hiddenSSID;
    568             allowedKeyManagement   = (BitSet) source.allowedKeyManagement.clone();
    569             allowedProtocols       = (BitSet) source.allowedProtocols.clone();
    570             allowedAuthAlgorithms  = (BitSet) source.allowedAuthAlgorithms.clone();
    571             allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
    572             allowedGroupCiphers    = (BitSet) source.allowedGroupCiphers.clone();
    573 
    574             enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
    575 
    576             ipAssignment = source.ipAssignment;
    577             proxySettings = source.proxySettings;
    578             linkProperties = new LinkProperties(source.linkProperties);
    579         }
    580     }
    581 
    582     /** Implement the Parcelable interface {@hide} */
    583     public void writeToParcel(Parcel dest, int flags) {
    584         dest.writeInt(networkId);
    585         dest.writeInt(status);
    586         dest.writeInt(disableReason);
    587         dest.writeString(SSID);
    588         dest.writeString(BSSID);
    589         dest.writeString(preSharedKey);
    590         for (String wepKey : wepKeys) {
    591             dest.writeString(wepKey);
    592         }
    593         dest.writeInt(wepTxKeyIndex);
    594         dest.writeInt(priority);
    595         dest.writeInt(hiddenSSID ? 1 : 0);
    596 
    597         writeBitSet(dest, allowedKeyManagement);
    598         writeBitSet(dest, allowedProtocols);
    599         writeBitSet(dest, allowedAuthAlgorithms);
    600         writeBitSet(dest, allowedPairwiseCiphers);
    601         writeBitSet(dest, allowedGroupCiphers);
    602 
    603         dest.writeParcelable(enterpriseConfig, flags);
    604 
    605         dest.writeString(ipAssignment.name());
    606         dest.writeString(proxySettings.name());
    607         dest.writeParcelable(linkProperties, flags);
    608     }
    609 
    610     /** Implement the Parcelable interface {@hide} */
    611     public static final Creator<WifiConfiguration> CREATOR =
    612         new Creator<WifiConfiguration>() {
    613             public WifiConfiguration createFromParcel(Parcel in) {
    614                 WifiConfiguration config = new WifiConfiguration();
    615                 config.networkId = in.readInt();
    616                 config.status = in.readInt();
    617                 config.disableReason = in.readInt();
    618                 config.SSID = in.readString();
    619                 config.BSSID = in.readString();
    620                 config.preSharedKey = in.readString();
    621                 for (int i = 0; i < config.wepKeys.length; i++) {
    622                     config.wepKeys[i] = in.readString();
    623                 }
    624                 config.wepTxKeyIndex = in.readInt();
    625                 config.priority = in.readInt();
    626                 config.hiddenSSID = in.readInt() != 0;
    627                 config.allowedKeyManagement   = readBitSet(in);
    628                 config.allowedProtocols       = readBitSet(in);
    629                 config.allowedAuthAlgorithms  = readBitSet(in);
    630                 config.allowedPairwiseCiphers = readBitSet(in);
    631                 config.allowedGroupCiphers    = readBitSet(in);
    632 
    633                 config.enterpriseConfig = in.readParcelable(null);
    634 
    635                 config.ipAssignment = IpAssignment.valueOf(in.readString());
    636                 config.proxySettings = ProxySettings.valueOf(in.readString());
    637                 config.linkProperties = in.readParcelable(null);
    638 
    639                 return config;
    640             }
    641 
    642             public WifiConfiguration[] newArray(int size) {
    643                 return new WifiConfiguration[size];
    644             }
    645         };
    646 }
    647