Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2010 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.content.Context;
     20 import android.content.Intent;
     21 import android.net.DhcpInfoInternal;
     22 import android.net.LinkAddress;
     23 import android.net.LinkProperties;
     24 import android.net.NetworkUtils;
     25 import android.net.ProxyProperties;
     26 import android.net.RouteInfo;
     27 import android.net.wifi.WifiConfiguration.IpAssignment;
     28 import android.net.wifi.WifiConfiguration.KeyMgmt;
     29 import android.net.wifi.WifiConfiguration.ProxySettings;
     30 import android.net.wifi.WifiConfiguration.Status;
     31 import android.net.wifi.NetworkUpdateResult;
     32 import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
     33 import android.os.Environment;
     34 import android.text.TextUtils;
     35 import android.util.Log;
     36 
     37 import java.io.BufferedInputStream;
     38 import java.io.BufferedOutputStream;
     39 import java.io.DataInputStream;
     40 import java.io.DataOutputStream;
     41 import java.io.EOFException;
     42 import java.io.FileInputStream;
     43 import java.io.FileOutputStream;
     44 import java.io.IOException;
     45 import java.net.InetAddress;
     46 import java.net.UnknownHostException;
     47 import java.util.ArrayList;
     48 import java.util.BitSet;
     49 import java.util.Collection;
     50 import java.util.HashMap;
     51 import java.util.Iterator;
     52 import java.util.List;
     53 
     54 /**
     55  * This class provides the API to manage configured
     56  * wifi networks. The API is not thread safe is being
     57  * used only from WifiStateMachine.
     58  *
     59  * It deals with the following
     60  * - Add/update/remove a WifiConfiguration
     61  *   The configuration contains two types of information.
     62  *     = IP and proxy configuration that is handled by WifiConfigStore and
     63  *       is saved to disk on any change.
     64  *
     65  *       The format of configuration file is as follows:
     66  *       <version>
     67  *       <netA_key1><netA_value1><netA_key2><netA_value2>...<EOS>
     68  *       <netB_key1><netB_value1><netB_key2><netB_value2>...<EOS>
     69  *       ..
     70  *
     71  *       (key, value) pairs for a given network are grouped together and can
     72  *       be in any order. A EOS at the end of a set of (key, value) pairs
     73  *       indicates that the next set of (key, value) pairs are for a new
     74  *       network. A network is identified by a unique ID_KEY. If there is no
     75  *       ID_KEY in the (key, value) pairs, the data is discarded.
     76  *
     77  *       An invalid version on read would result in discarding the contents of
     78  *       the file. On the next write, the latest version is written to file.
     79  *
     80  *       Any failures during read or write to the configuration file are ignored
     81  *       without reporting to the user since the likelihood of these errors are
     82  *       low and the impact on connectivity is low.
     83  *
     84  *     = SSID & security details that is pushed to the supplicant.
     85  *       supplicant saves these details to the disk on calling
     86  *       saveConfigCommand().
     87  *
     88  *       We have two kinds of APIs exposed:
     89  *        > public API calls that provide fine grained control
     90  *          - enableNetwork, disableNetwork, addOrUpdateNetwork(),
     91  *          removeNetwork(). For these calls, the config is not persisted
     92  *          to the disk. (TODO: deprecate these calls in WifiManager)
     93  *        > The new API calls - selectNetwork(), saveNetwork() & forgetNetwork().
     94  *          These calls persist the supplicant config to disk.
     95  *
     96  * - Maintain a list of configured networks for quick access
     97  *
     98  */
     99 class WifiConfigStore {
    100 
    101     private static Context sContext;
    102     private static final String TAG = "WifiConfigStore";
    103     private static final boolean DBG = false;
    104 
    105     /* configured networks with network id as the key */
    106     private static HashMap<Integer, WifiConfiguration> sConfiguredNetworks =
    107             new HashMap<Integer, WifiConfiguration>();
    108 
    109     /* A network id is a unique identifier for a network configured in the
    110      * supplicant. Network ids are generated when the supplicant reads
    111      * the configuration file at start and can thus change for networks.
    112      * We store the IP configuration for networks along with a unique id
    113      * that is generated from SSID and security type of the network. A mapping
    114      * from the generated unique id to network id of the network is needed to
    115      * map supplicant config to IP configuration. */
    116     private static HashMap<Integer, Integer> sNetworkIds =
    117             new HashMap<Integer, Integer>();
    118 
    119     /* Tracks the highest priority of configured networks */
    120     private static int sLastPriority = -1;
    121 
    122     private static final String ipConfigFile = Environment.getDataDirectory() +
    123             "/misc/wifi/ipconfig.txt";
    124 
    125     private static final int IPCONFIG_FILE_VERSION = 2;
    126 
    127     /* IP and proxy configuration keys */
    128     private static final String ID_KEY = "id";
    129     private static final String IP_ASSIGNMENT_KEY = "ipAssignment";
    130     private static final String LINK_ADDRESS_KEY = "linkAddress";
    131     private static final String GATEWAY_KEY = "gateway";
    132     private static final String DNS_KEY = "dns";
    133     private static final String PROXY_SETTINGS_KEY = "proxySettings";
    134     private static final String PROXY_HOST_KEY = "proxyHost";
    135     private static final String PROXY_PORT_KEY = "proxyPort";
    136     private static final String EXCLUSION_LIST_KEY = "exclusionList";
    137     private static final String EOS = "eos";
    138 
    139     /**
    140      * Initialize context, fetch the list of configured networks
    141      * and enable all stored networks in supplicant.
    142      */
    143     static void initialize(Context context) {
    144         if (DBG) log("Loading config and enabling all networks");
    145         sContext = context;
    146         loadConfiguredNetworks();
    147         enableAllNetworks();
    148     }
    149 
    150     /**
    151      * Fetch the list of currently configured networks
    152      * @return List of networks
    153      */
    154     static List<WifiConfiguration> getConfiguredNetworks() {
    155         List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
    156         synchronized (sConfiguredNetworks) {
    157             for(WifiConfiguration config : sConfiguredNetworks.values()) {
    158                 networks.add(new WifiConfiguration(config));
    159             }
    160         }
    161         return networks;
    162     }
    163 
    164     /**
    165      * enable all networks and save config. This will be a no-op if the list
    166      * of configured networks indicates all networks as being enabled
    167      */
    168     static void enableAllNetworks() {
    169         boolean networkEnabledStateChanged = false;
    170         synchronized (sConfiguredNetworks) {
    171             for(WifiConfiguration config : sConfiguredNetworks.values()) {
    172                 if(config != null && config.status == Status.DISABLED) {
    173                     if(WifiNative.enableNetworkCommand(config.networkId, false)) {
    174                         networkEnabledStateChanged = true;
    175                         config.status = Status.ENABLED;
    176                     } else {
    177                         loge("Enable network failed on " + config.networkId);
    178                     }
    179                 }
    180             }
    181         }
    182 
    183         if (networkEnabledStateChanged) {
    184             WifiNative.saveConfigCommand();
    185             sendConfiguredNetworksChangedBroadcast();
    186         }
    187     }
    188 
    189     /**
    190      * Selects the specified network config for connection. This involves
    191      * addition/update of the specified config, updating the priority of
    192      * all the networks and enabling the given network while disabling others.
    193      *
    194      * Selecting a network will leave the other networks disabled and
    195      * a call to enableAllNetworks() needs to be issued upon a connection
    196      * or a failure event from supplicant
    197      *
    198      * @param config The configuration details in WifiConfiguration
    199      * @return the networkId now associated with the specified configuration
    200      */
    201     static int selectNetwork(WifiConfiguration config) {
    202         if (config != null) {
    203             NetworkUpdateResult result = addOrUpdateNetworkNative(config);
    204             int netId = result.getNetworkId();
    205             if (netId != INVALID_NETWORK_ID) {
    206                 selectNetwork(netId);
    207             } else {
    208                 loge("Failed to update network " + config);
    209             }
    210             return netId;
    211         }
    212         return INVALID_NETWORK_ID;
    213     }
    214 
    215     /**
    216      * Selects the specified network for connection. This involves
    217      * updating the priority of all the networks and enabling the given
    218      * network while disabling others.
    219      *
    220      * Selecting a network will leave the other networks disabled and
    221      * a call to enableAllNetworks() needs to be issued upon a connection
    222      * or a failure event from supplicant
    223      *
    224      * @param netId network to select for connection
    225      */
    226     static void selectNetwork(int netId) {
    227         // Reset the priority of each network at start or if it goes too high.
    228         if (sLastPriority == -1 || sLastPriority > 1000000) {
    229             synchronized (sConfiguredNetworks) {
    230                 for(WifiConfiguration config : sConfiguredNetworks.values()) {
    231                     if (config.networkId != INVALID_NETWORK_ID) {
    232                         config.priority = 0;
    233                         addOrUpdateNetworkNative(config);
    234                     }
    235                 }
    236             }
    237             sLastPriority = 0;
    238         }
    239 
    240         // Set to the highest priority and save the configuration.
    241         WifiConfiguration config = new WifiConfiguration();
    242         config.networkId = netId;
    243         config.priority = ++sLastPriority;
    244 
    245         addOrUpdateNetworkNative(config);
    246         WifiNative.saveConfigCommand();
    247 
    248         /* Enable the given network while disabling all other networks */
    249         enableNetworkWithoutBroadcast(netId, true);
    250 
    251        /* Avoid saving the config & sending a broadcast to prevent settings
    252         * from displaying a disabled list of networks */
    253     }
    254 
    255     /**
    256      * Add/update the specified configuration and save config
    257      *
    258      * @param config WifiConfiguration to be saved
    259      */
    260     static NetworkUpdateResult saveNetwork(WifiConfiguration config) {
    261         boolean newNetwork = (config.networkId == INVALID_NETWORK_ID);
    262         NetworkUpdateResult result = addOrUpdateNetworkNative(config);
    263         int netId = result.getNetworkId();
    264         /* enable a new network */
    265         if (newNetwork && netId != INVALID_NETWORK_ID) {
    266             WifiNative.enableNetworkCommand(netId, false);
    267             synchronized (sConfiguredNetworks) {
    268                 sConfiguredNetworks.get(netId).status = Status.ENABLED;
    269             }
    270         }
    271         WifiNative.saveConfigCommand();
    272         sendConfiguredNetworksChangedBroadcast();
    273         return result;
    274     }
    275 
    276     /**
    277      * Forget the specified network and save config
    278      *
    279      * @param netId network to forget
    280      */
    281     static void forgetNetwork(int netId) {
    282         if (WifiNative.removeNetworkCommand(netId)) {
    283             WifiNative.saveConfigCommand();
    284             synchronized (sConfiguredNetworks) {
    285                 WifiConfiguration config = sConfiguredNetworks.get(netId);
    286                 if (config != null) {
    287                     sConfiguredNetworks.remove(netId);
    288                     sNetworkIds.remove(configKey(config));
    289                 }
    290             }
    291             writeIpAndProxyConfigurations();
    292             sendConfiguredNetworksChangedBroadcast();
    293         } else {
    294             loge("Failed to remove network " + netId);
    295         }
    296     }
    297 
    298     /**
    299      * Add/update a network. Note that there is no saveConfig operation.
    300      * This function is retained for compatibility with the public
    301      * API. The more powerful saveNetwork() is used by the
    302      * state machine
    303      *
    304      * @param config wifi configuration to add/update
    305      */
    306     static int addOrUpdateNetwork(WifiConfiguration config) {
    307         NetworkUpdateResult result = addOrUpdateNetworkNative(config);
    308         sendConfiguredNetworksChangedBroadcast();
    309         return result.getNetworkId();
    310     }
    311 
    312     /**
    313      * Remove a network. Note that there is no saveConfig operation.
    314      * This function is retained for compatibility with the public
    315      * API. The more powerful forgetNetwork() is used by the
    316      * state machine for network removal
    317      *
    318      * @param netId network to be removed
    319      */
    320     static boolean removeNetwork(int netId) {
    321         boolean ret = WifiNative.removeNetworkCommand(netId);
    322         synchronized (sConfiguredNetworks) {
    323             if (ret) {
    324                 WifiConfiguration config = sConfiguredNetworks.get(netId);
    325                 if (config != null) {
    326                     sConfiguredNetworks.remove(netId);
    327                     sNetworkIds.remove(configKey(config));
    328                 }
    329             }
    330         }
    331         sendConfiguredNetworksChangedBroadcast();
    332         return ret;
    333     }
    334 
    335     /**
    336      * Enable a network. Note that there is no saveConfig operation.
    337      * This function is retained for compatibility with the public
    338      * API. The more powerful selectNetwork()/saveNetwork() is used by the
    339      * state machine for connecting to a network
    340      *
    341      * @param netId network to be removed
    342      */
    343     static boolean enableNetwork(int netId, boolean disableOthers) {
    344         boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers);
    345         sendConfiguredNetworksChangedBroadcast();
    346         return ret;
    347     }
    348 
    349     static boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) {
    350         boolean ret = WifiNative.enableNetworkCommand(netId, disableOthers);
    351 
    352         synchronized (sConfiguredNetworks) {
    353             WifiConfiguration config = sConfiguredNetworks.get(netId);
    354             if (config != null) config.status = Status.ENABLED;
    355         }
    356 
    357         if (disableOthers) {
    358             markAllNetworksDisabledExcept(netId);
    359         }
    360         return ret;
    361     }
    362 
    363     /**
    364      * Disable a network. Note that there is no saveConfig operation.
    365      * @param netId network to be disabled
    366      */
    367     static boolean disableNetwork(int netId) {
    368         return disableNetwork(netId, WifiConfiguration.DISABLED_UNKNOWN_REASON);
    369     }
    370 
    371     /**
    372      * Disable a network. Note that there is no saveConfig operation.
    373      * @param netId network to be disabled
    374      * @param reason reason code network was disabled
    375      */
    376     static boolean disableNetwork(int netId, int reason) {
    377         boolean ret = WifiNative.disableNetworkCommand(netId);
    378         synchronized (sConfiguredNetworks) {
    379             WifiConfiguration config = sConfiguredNetworks.get(netId);
    380             /* Only change the reason if the network was not previously disabled */
    381             if (config != null && config.status != Status.DISABLED) {
    382                 config.status = Status.DISABLED;
    383                 config.disableReason = reason;
    384             }
    385         }
    386         sendConfiguredNetworksChangedBroadcast();
    387         return ret;
    388     }
    389 
    390     /**
    391      * Save the configured networks in supplicant to disk
    392      */
    393     static boolean saveConfig() {
    394         return WifiNative.saveConfigCommand();
    395     }
    396 
    397     /**
    398      * Start WPS pin method configuration with pin obtained
    399      * from the access point
    400      */
    401     static WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) {
    402         WpsResult result = new WpsResult();
    403         if (WifiNative.startWpsWithPinFromAccessPointCommand(config.BSSID, config.pin)) {
    404             /* WPS leaves all networks disabled */
    405             markAllNetworksDisabled();
    406             result.status = WpsResult.Status.SUCCESS;
    407         } else {
    408             loge("Failed to start WPS pin method configuration");
    409             result.status = WpsResult.Status.FAILURE;
    410         }
    411         return result;
    412     }
    413 
    414     /**
    415      * Start WPS pin method configuration with pin obtained
    416      * from the device
    417      * @return WpsResult indicating status and pin
    418      */
    419     static WpsResult startWpsWithPinFromDevice(WpsInfo config) {
    420         WpsResult result = new WpsResult();
    421         result.pin = WifiNative.startWpsWithPinFromDeviceCommand(config.BSSID);
    422         /* WPS leaves all networks disabled */
    423         if (!TextUtils.isEmpty(result.pin)) {
    424             markAllNetworksDisabled();
    425             result.status = WpsResult.Status.SUCCESS;
    426         } else {
    427             loge("Failed to start WPS pin method configuration");
    428             result.status = WpsResult.Status.FAILURE;
    429         }
    430         return result;
    431     }
    432 
    433     /**
    434      * Start WPS push button configuration
    435      */
    436     static WpsResult startWpsPbc(WpsInfo config) {
    437         WpsResult result = new WpsResult();
    438         if (WifiNative.startWpsPbcCommand(config.BSSID)) {
    439             /* WPS leaves all networks disabled */
    440             markAllNetworksDisabled();
    441             result.status = WpsResult.Status.SUCCESS;
    442         } else {
    443             loge("Failed to start WPS push button configuration");
    444             result.status = WpsResult.Status.FAILURE;
    445         }
    446         return result;
    447     }
    448 
    449     /**
    450      * Fetch the link properties for a given network id
    451      */
    452     static LinkProperties getLinkProperties(int netId) {
    453         synchronized (sConfiguredNetworks) {
    454             WifiConfiguration config = sConfiguredNetworks.get(netId);
    455             if (config != null) return new LinkProperties(config.linkProperties);
    456         }
    457         return null;
    458     }
    459 
    460     /**
    461      * get IP configuration for a given network id
    462      * TODO: We cannot handle IPv6 addresses for configuration
    463      *       right now until NetworkUtils is fixed. When we do
    464      *       that, we should remove handling DhcpInfo and move
    465      *       to using LinkProperties
    466      */
    467     static DhcpInfoInternal getIpConfiguration(int netId) {
    468         DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
    469         LinkProperties linkProperties = getLinkProperties(netId);
    470 
    471         if (linkProperties != null) {
    472             Iterator<LinkAddress> iter = linkProperties.getLinkAddresses().iterator();
    473             if (iter.hasNext()) {
    474                 LinkAddress linkAddress = iter.next();
    475                 dhcpInfoInternal.ipAddress = linkAddress.getAddress().getHostAddress();
    476                 for (RouteInfo route : linkProperties.getRoutes()) {
    477                     dhcpInfoInternal.addRoute(route);
    478                 }
    479                 dhcpInfoInternal.prefixLength = linkAddress.getNetworkPrefixLength();
    480                 Iterator<InetAddress> dnsIterator = linkProperties.getDnses().iterator();
    481                 dhcpInfoInternal.dns1 = dnsIterator.next().getHostAddress();
    482                 if (dnsIterator.hasNext()) {
    483                     dhcpInfoInternal.dns2 = dnsIterator.next().getHostAddress();
    484                 }
    485             }
    486         }
    487         return dhcpInfoInternal;
    488     }
    489 
    490     /**
    491      * set IP configuration for a given network id
    492      */
    493     static void setIpConfiguration(int netId, DhcpInfoInternal dhcpInfo) {
    494         LinkProperties linkProperties = dhcpInfo.makeLinkProperties();
    495 
    496         synchronized (sConfiguredNetworks) {
    497             WifiConfiguration config = sConfiguredNetworks.get(netId);
    498             if (config != null) {
    499                 // add old proxy details
    500                 if(config.linkProperties != null) {
    501                     linkProperties.setHttpProxy(config.linkProperties.getHttpProxy());
    502                 }
    503                 config.linkProperties = linkProperties;
    504             }
    505         }
    506     }
    507 
    508     /**
    509      * clear IP configuration for a given network id
    510      */
    511     static void clearIpConfiguration(int netId) {
    512         synchronized (sConfiguredNetworks) {
    513             WifiConfiguration config = sConfiguredNetworks.get(netId);
    514             if (config != null && config.linkProperties != null) {
    515                 // Clear everything except proxy
    516                 ProxyProperties proxy = config.linkProperties.getHttpProxy();
    517                 config.linkProperties.clear();
    518                 config.linkProperties.setHttpProxy(proxy);
    519             }
    520         }
    521     }
    522 
    523 
    524     /**
    525      * Fetch the proxy properties for a given network id
    526      */
    527     static ProxyProperties getProxyProperties(int netId) {
    528         LinkProperties linkProperties = getLinkProperties(netId);
    529         if (linkProperties != null) {
    530             return new ProxyProperties(linkProperties.getHttpProxy());
    531         }
    532         return null;
    533     }
    534 
    535     /**
    536      * Return if the specified network is using static IP
    537      */
    538     static boolean isUsingStaticIp(int netId) {
    539         synchronized (sConfiguredNetworks) {
    540             WifiConfiguration config = sConfiguredNetworks.get(netId);
    541             if (config != null && config.ipAssignment == IpAssignment.STATIC) {
    542                 return true;
    543             }
    544         }
    545         return false;
    546     }
    547 
    548     private static void sendConfiguredNetworksChangedBroadcast() {
    549         Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
    550         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    551         sContext.sendBroadcast(intent);
    552     }
    553 
    554     static void loadConfiguredNetworks() {
    555         String listStr = WifiNative.listNetworksCommand();
    556         sLastPriority = 0;
    557 
    558         synchronized (sConfiguredNetworks) {
    559             sConfiguredNetworks.clear();
    560             sNetworkIds.clear();
    561 
    562             if (listStr == null)
    563                 return;
    564 
    565             String[] lines = listStr.split("\n");
    566             // Skip the first line, which is a header
    567             for (int i = 1; i < lines.length; i++) {
    568                 String[] result = lines[i].split("\t");
    569                 // network-id | ssid | bssid | flags
    570                 WifiConfiguration config = new WifiConfiguration();
    571                 try {
    572                     config.networkId = Integer.parseInt(result[0]);
    573                 } catch(NumberFormatException e) {
    574                     continue;
    575                 }
    576                 if (result.length > 3) {
    577                     if (result[3].indexOf("[CURRENT]") != -1)
    578                         config.status = WifiConfiguration.Status.CURRENT;
    579                     else if (result[3].indexOf("[DISABLED]") != -1)
    580                         config.status = WifiConfiguration.Status.DISABLED;
    581                     else
    582                         config.status = WifiConfiguration.Status.ENABLED;
    583                 } else {
    584                     config.status = WifiConfiguration.Status.ENABLED;
    585                 }
    586                 readNetworkVariables(config);
    587                 if (config.priority > sLastPriority) {
    588                     sLastPriority = config.priority;
    589                 }
    590                 sConfiguredNetworks.put(config.networkId, config);
    591                 sNetworkIds.put(configKey(config), config.networkId);
    592             }
    593         }
    594         readIpAndProxyConfigurations();
    595         sendConfiguredNetworksChangedBroadcast();
    596     }
    597 
    598     static void updateIpAndProxyFromWpsConfig(int netId, WpsInfo wpsConfig) {
    599         synchronized (sConfiguredNetworks) {
    600             WifiConfiguration config = sConfiguredNetworks.get(netId);
    601             if (config != null) {
    602                 config.ipAssignment = wpsConfig.ipAssignment;
    603                 config.proxySettings = wpsConfig.proxySettings;
    604                 config.linkProperties = wpsConfig.linkProperties;
    605                 writeIpAndProxyConfigurations();
    606             }
    607         }
    608     }
    609 
    610     /* Mark all networks except specified netId as disabled */
    611     private static void markAllNetworksDisabledExcept(int netId) {
    612         synchronized (sConfiguredNetworks) {
    613             for(WifiConfiguration config : sConfiguredNetworks.values()) {
    614                 if(config != null && config.networkId != netId) {
    615                     if (config.status != Status.DISABLED) {
    616                         config.status = Status.DISABLED;
    617                         config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON;
    618                     }
    619                 }
    620             }
    621         }
    622     }
    623 
    624     private static void markAllNetworksDisabled() {
    625         markAllNetworksDisabledExcept(INVALID_NETWORK_ID);
    626     }
    627 
    628     private static void writeIpAndProxyConfigurations() {
    629 
    630         DataOutputStream out = null;
    631         try {
    632             out = new DataOutputStream(new BufferedOutputStream(
    633                     new FileOutputStream(ipConfigFile)));
    634 
    635             out.writeInt(IPCONFIG_FILE_VERSION);
    636 
    637             synchronized (sConfiguredNetworks) {
    638                 for(WifiConfiguration config : sConfiguredNetworks.values()) {
    639                     boolean writeToFile = false;
    640 
    641                     try {
    642                         LinkProperties linkProperties = config.linkProperties;
    643                         switch (config.ipAssignment) {
    644                             case STATIC:
    645                                 out.writeUTF(IP_ASSIGNMENT_KEY);
    646                                 out.writeUTF(config.ipAssignment.toString());
    647                                 for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) {
    648                                     out.writeUTF(LINK_ADDRESS_KEY);
    649                                     out.writeUTF(linkAddr.getAddress().getHostAddress());
    650                                     out.writeInt(linkAddr.getNetworkPrefixLength());
    651                                 }
    652                                 for (RouteInfo route : linkProperties.getRoutes()) {
    653                                     out.writeUTF(GATEWAY_KEY);
    654                                     LinkAddress dest = route.getDestination();
    655                                     if (dest != null) {
    656                                         out.writeInt(1);
    657                                         out.writeUTF(dest.getAddress().getHostAddress());
    658                                         out.writeInt(dest.getNetworkPrefixLength());
    659                                     } else {
    660                                         out.writeInt(0);
    661                                     }
    662                                     if (route.getGateway() != null) {
    663                                         out.writeInt(1);
    664                                         out.writeUTF(route.getGateway().getHostAddress());
    665                                     } else {
    666                                         out.writeInt(0);
    667                                     }
    668                                 }
    669                                 for (InetAddress inetAddr : linkProperties.getDnses()) {
    670                                     out.writeUTF(DNS_KEY);
    671                                     out.writeUTF(inetAddr.getHostAddress());
    672                                 }
    673                                 writeToFile = true;
    674                                 break;
    675                             case DHCP:
    676                                 out.writeUTF(IP_ASSIGNMENT_KEY);
    677                                 out.writeUTF(config.ipAssignment.toString());
    678                                 writeToFile = true;
    679                                 break;
    680                             case UNASSIGNED:
    681                                 /* Ignore */
    682                                 break;
    683                             default:
    684                                 loge("Ignore invalid ip assignment while writing");
    685                                 break;
    686                         }
    687 
    688                         switch (config.proxySettings) {
    689                             case STATIC:
    690                                 ProxyProperties proxyProperties = linkProperties.getHttpProxy();
    691                                 String exclusionList = proxyProperties.getExclusionList();
    692                                 out.writeUTF(PROXY_SETTINGS_KEY);
    693                                 out.writeUTF(config.proxySettings.toString());
    694                                 out.writeUTF(PROXY_HOST_KEY);
    695                                 out.writeUTF(proxyProperties.getHost());
    696                                 out.writeUTF(PROXY_PORT_KEY);
    697                                 out.writeInt(proxyProperties.getPort());
    698                                 out.writeUTF(EXCLUSION_LIST_KEY);
    699                                 out.writeUTF(exclusionList);
    700                                 writeToFile = true;
    701                                 break;
    702                             case NONE:
    703                                 out.writeUTF(PROXY_SETTINGS_KEY);
    704                                 out.writeUTF(config.proxySettings.toString());
    705                                 writeToFile = true;
    706                                 break;
    707                             case UNASSIGNED:
    708                                 /* Ignore */
    709                                 break;
    710                             default:
    711                                 loge("Ignore invalid proxy settings while writing");
    712                                 break;
    713                         }
    714                         if (writeToFile) {
    715                             out.writeUTF(ID_KEY);
    716                             out.writeInt(configKey(config));
    717                         }
    718                     } catch (NullPointerException e) {
    719                         loge("Failure in writing " + config.linkProperties + e);
    720                     }
    721                     out.writeUTF(EOS);
    722                 }
    723             }
    724 
    725         } catch (IOException e) {
    726             loge("Error writing data file");
    727         } finally {
    728             if (out != null) {
    729                 try {
    730                     out.close();
    731                 } catch (Exception e) {}
    732             }
    733         }
    734     }
    735 
    736     private static void readIpAndProxyConfigurations() {
    737 
    738         DataInputStream in = null;
    739         try {
    740             in = new DataInputStream(new BufferedInputStream(new FileInputStream(
    741                     ipConfigFile)));
    742 
    743             int version = in.readInt();
    744             if (version != 2 && version != 1) {
    745                 loge("Bad version on IP configuration file, ignore read");
    746                 return;
    747             }
    748 
    749             while (true) {
    750                 int id = -1;
    751                 IpAssignment ipAssignment = IpAssignment.UNASSIGNED;
    752                 ProxySettings proxySettings = ProxySettings.UNASSIGNED;
    753                 LinkProperties linkProperties = new LinkProperties();
    754                 String proxyHost = null;
    755                 int proxyPort = -1;
    756                 String exclusionList = null;
    757                 String key;
    758 
    759                 do {
    760                     key = in.readUTF();
    761                     try {
    762                         if (key.equals(ID_KEY)) {
    763                             id = in.readInt();
    764                         } else if (key.equals(IP_ASSIGNMENT_KEY)) {
    765                             ipAssignment = IpAssignment.valueOf(in.readUTF());
    766                         } else if (key.equals(LINK_ADDRESS_KEY)) {
    767                             LinkAddress linkAddr = new LinkAddress(
    768                                     NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt());
    769                             linkProperties.addLinkAddress(linkAddr);
    770                         } else if (key.equals(GATEWAY_KEY)) {
    771                             LinkAddress dest = null;
    772                             InetAddress gateway = null;
    773                             if (version == 1) {
    774                                 // only supported default gateways - leave the dest/prefix empty
    775                                 gateway = NetworkUtils.numericToInetAddress(in.readUTF());
    776                             } else {
    777                                 if (in.readInt() == 1) {
    778                                     dest = new LinkAddress(
    779                                             NetworkUtils.numericToInetAddress(in.readUTF()),
    780                                             in.readInt());
    781                                 }
    782                                 if (in.readInt() == 1) {
    783                                     gateway = NetworkUtils.numericToInetAddress(in.readUTF());
    784                                 }
    785                             }
    786                             linkProperties.addRoute(new RouteInfo(dest, gateway));
    787                         } else if (key.equals(DNS_KEY)) {
    788                             linkProperties.addDns(
    789                                     NetworkUtils.numericToInetAddress(in.readUTF()));
    790                         } else if (key.equals(PROXY_SETTINGS_KEY)) {
    791                             proxySettings = ProxySettings.valueOf(in.readUTF());
    792                         } else if (key.equals(PROXY_HOST_KEY)) {
    793                             proxyHost = in.readUTF();
    794                         } else if (key.equals(PROXY_PORT_KEY)) {
    795                             proxyPort = in.readInt();
    796                         } else if (key.equals(EXCLUSION_LIST_KEY)) {
    797                             exclusionList = in.readUTF();
    798                         } else if (key.equals(EOS)) {
    799                             break;
    800                         } else {
    801                             loge("Ignore unknown key " + key + "while reading");
    802                         }
    803                     } catch (IllegalArgumentException e) {
    804                         loge("Ignore invalid address while reading" + e);
    805                     }
    806                 } while (true);
    807 
    808                 if (id != -1) {
    809                     synchronized (sConfiguredNetworks) {
    810                         WifiConfiguration config = sConfiguredNetworks.get(
    811                                 sNetworkIds.get(id));
    812 
    813                         if (config == null) {
    814                             loge("configuration found for missing network, ignored");
    815                         } else {
    816                             config.linkProperties = linkProperties;
    817                             switch (ipAssignment) {
    818                                 case STATIC:
    819                                 case DHCP:
    820                                     config.ipAssignment = ipAssignment;
    821                                     break;
    822                                 case UNASSIGNED:
    823                                     //Ignore
    824                                     break;
    825                                 default:
    826                                     loge("Ignore invalid ip assignment while reading");
    827                                     break;
    828                             }
    829 
    830                             switch (proxySettings) {
    831                                 case STATIC:
    832                                     config.proxySettings = proxySettings;
    833                                     ProxyProperties proxyProperties =
    834                                         new ProxyProperties(proxyHost, proxyPort, exclusionList);
    835                                     linkProperties.setHttpProxy(proxyProperties);
    836                                     break;
    837                                 case NONE:
    838                                     config.proxySettings = proxySettings;
    839                                     break;
    840                                 case UNASSIGNED:
    841                                     //Ignore
    842                                     break;
    843                                 default:
    844                                     loge("Ignore invalid proxy settings while reading");
    845                                     break;
    846                             }
    847                         }
    848                     }
    849                 } else {
    850                     loge("Missing id while parsing configuration");
    851                 }
    852             }
    853         } catch (EOFException ignore) {
    854         } catch (IOException e) {
    855             loge("Error parsing configuration" + e);
    856         } finally {
    857             if (in != null) {
    858                 try {
    859                     in.close();
    860                 } catch (Exception e) {}
    861             }
    862         }
    863     }
    864 
    865     private static NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config) {
    866         /*
    867          * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty
    868          * network configuration. Otherwise, the networkId should
    869          * refer to an existing configuration.
    870          */
    871         int netId = config.networkId;
    872         boolean newNetwork = false;
    873         // networkId of INVALID_NETWORK_ID means we want to create a new network
    874         if (netId == INVALID_NETWORK_ID) {
    875             Integer savedNetId = sNetworkIds.get(configKey(config));
    876             if (savedNetId != null) {
    877                 netId = savedNetId;
    878             } else {
    879                 newNetwork = true;
    880                 netId = WifiNative.addNetworkCommand();
    881                 if (netId < 0) {
    882                     loge("Failed to add a network!");
    883                     return new NetworkUpdateResult(INVALID_NETWORK_ID);
    884                 }
    885             }
    886         }
    887 
    888         boolean updateFailed = true;
    889 
    890         setVariables: {
    891 
    892             if (config.SSID != null &&
    893                     !WifiNative.setNetworkVariableCommand(
    894                         netId,
    895                         WifiConfiguration.ssidVarName,
    896                         config.SSID)) {
    897                 loge("failed to set SSID: "+config.SSID);
    898                 break setVariables;
    899             }
    900 
    901             if (config.BSSID != null &&
    902                     !WifiNative.setNetworkVariableCommand(
    903                         netId,
    904                         WifiConfiguration.bssidVarName,
    905                         config.BSSID)) {
    906                 loge("failed to set BSSID: "+config.BSSID);
    907                 break setVariables;
    908             }
    909 
    910             String allowedKeyManagementString =
    911                 makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings);
    912             if (config.allowedKeyManagement.cardinality() != 0 &&
    913                     !WifiNative.setNetworkVariableCommand(
    914                         netId,
    915                         WifiConfiguration.KeyMgmt.varName,
    916                         allowedKeyManagementString)) {
    917                 loge("failed to set key_mgmt: "+
    918                         allowedKeyManagementString);
    919                 break setVariables;
    920             }
    921 
    922             String allowedProtocolsString =
    923                 makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings);
    924             if (config.allowedProtocols.cardinality() != 0 &&
    925                     !WifiNative.setNetworkVariableCommand(
    926                         netId,
    927                         WifiConfiguration.Protocol.varName,
    928                         allowedProtocolsString)) {
    929                 loge("failed to set proto: "+
    930                         allowedProtocolsString);
    931                 break setVariables;
    932             }
    933 
    934             String allowedAuthAlgorithmsString =
    935                 makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings);
    936             if (config.allowedAuthAlgorithms.cardinality() != 0 &&
    937                     !WifiNative.setNetworkVariableCommand(
    938                         netId,
    939                         WifiConfiguration.AuthAlgorithm.varName,
    940                         allowedAuthAlgorithmsString)) {
    941                 loge("failed to set auth_alg: "+
    942                         allowedAuthAlgorithmsString);
    943                 break setVariables;
    944             }
    945 
    946             String allowedPairwiseCiphersString =
    947                     makeString(config.allowedPairwiseCiphers,
    948                     WifiConfiguration.PairwiseCipher.strings);
    949             if (config.allowedPairwiseCiphers.cardinality() != 0 &&
    950                     !WifiNative.setNetworkVariableCommand(
    951                         netId,
    952                         WifiConfiguration.PairwiseCipher.varName,
    953                         allowedPairwiseCiphersString)) {
    954                 loge("failed to set pairwise: "+
    955                         allowedPairwiseCiphersString);
    956                 break setVariables;
    957             }
    958 
    959             String allowedGroupCiphersString =
    960                 makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings);
    961             if (config.allowedGroupCiphers.cardinality() != 0 &&
    962                     !WifiNative.setNetworkVariableCommand(
    963                         netId,
    964                         WifiConfiguration.GroupCipher.varName,
    965                         allowedGroupCiphersString)) {
    966                 loge("failed to set group: "+
    967                         allowedGroupCiphersString);
    968                 break setVariables;
    969             }
    970 
    971             // Prevent client screw-up by passing in a WifiConfiguration we gave it
    972             // by preventing "*" as a key.
    973             if (config.preSharedKey != null && !config.preSharedKey.equals("*") &&
    974                     !WifiNative.setNetworkVariableCommand(
    975                         netId,
    976                         WifiConfiguration.pskVarName,
    977                         config.preSharedKey)) {
    978                 loge("failed to set psk");
    979                 break setVariables;
    980             }
    981 
    982             boolean hasSetKey = false;
    983             if (config.wepKeys != null) {
    984                 for (int i = 0; i < config.wepKeys.length; i++) {
    985                     // Prevent client screw-up by passing in a WifiConfiguration we gave it
    986                     // by preventing "*" as a key.
    987                     if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) {
    988                         if (!WifiNative.setNetworkVariableCommand(
    989                                     netId,
    990                                     WifiConfiguration.wepKeyVarNames[i],
    991                                     config.wepKeys[i])) {
    992                             loge("failed to set wep_key" + i + ": " + config.wepKeys[i]);
    993                             break setVariables;
    994                         }
    995                         hasSetKey = true;
    996                     }
    997                 }
    998             }
    999 
   1000             if (hasSetKey) {
   1001                 if (!WifiNative.setNetworkVariableCommand(
   1002                             netId,
   1003                             WifiConfiguration.wepTxKeyIdxVarName,
   1004                             Integer.toString(config.wepTxKeyIndex))) {
   1005                     loge("failed to set wep_tx_keyidx: " + config.wepTxKeyIndex);
   1006                     break setVariables;
   1007                 }
   1008             }
   1009 
   1010             if (!WifiNative.setNetworkVariableCommand(
   1011                         netId,
   1012                         WifiConfiguration.priorityVarName,
   1013                         Integer.toString(config.priority))) {
   1014                 loge(config.SSID + ": failed to set priority: "
   1015                         +config.priority);
   1016                 break setVariables;
   1017             }
   1018 
   1019             if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand(
   1020                         netId,
   1021                         WifiConfiguration.hiddenSSIDVarName,
   1022                         Integer.toString(config.hiddenSSID ? 1 : 0))) {
   1023                 loge(config.SSID + ": failed to set hiddenSSID: "+
   1024                         config.hiddenSSID);
   1025                 break setVariables;
   1026             }
   1027 
   1028             for (WifiConfiguration.EnterpriseField field
   1029                     : config.enterpriseFields) {
   1030                 String varName = field.varName();
   1031                 String value = field.value();
   1032                 if (value != null) {
   1033                     if (field != config.eap) {
   1034                         value = (value.length() == 0) ? "NULL" : convertToQuotedString(value);
   1035                     }
   1036                     if (!WifiNative.setNetworkVariableCommand(
   1037                                 netId,
   1038                                 varName,
   1039                                 value)) {
   1040                         loge(config.SSID + ": failed to set " + varName +
   1041                                 ": " + value);
   1042                         break setVariables;
   1043                     }
   1044                 }
   1045             }
   1046             updateFailed = false;
   1047         }
   1048 
   1049         if (updateFailed) {
   1050             if (newNetwork) {
   1051                 WifiNative.removeNetworkCommand(netId);
   1052                 loge("Failed to set a network variable, removed network: " + netId);
   1053             }
   1054             return new NetworkUpdateResult(INVALID_NETWORK_ID);
   1055         }
   1056 
   1057         /* An update of the network variables requires reading them
   1058          * back from the supplicant to update sConfiguredNetworks.
   1059          * This is because some of the variables (SSID, wep keys &
   1060          * passphrases) reflect different values when read back than
   1061          * when written. For example, wep key is stored as * irrespective
   1062          * of the value sent to the supplicant
   1063          */
   1064         WifiConfiguration sConfig;
   1065         synchronized (sConfiguredNetworks) {
   1066             sConfig = sConfiguredNetworks.get(netId);
   1067         }
   1068         if (sConfig == null) {
   1069             sConfig = new WifiConfiguration();
   1070             sConfig.networkId = netId;
   1071         }
   1072 
   1073         readNetworkVariables(sConfig);
   1074 
   1075         synchronized (sConfiguredNetworks) {
   1076             sConfiguredNetworks.put(netId, sConfig);
   1077             sNetworkIds.put(configKey(sConfig), netId);
   1078         }
   1079 
   1080         NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(sConfig, config);
   1081         result.setNetworkId(netId);
   1082         return result;
   1083     }
   1084 
   1085     /* Compare current and new configuration and write to file on change */
   1086     private static NetworkUpdateResult writeIpAndProxyConfigurationsOnChange(
   1087             WifiConfiguration currentConfig,
   1088             WifiConfiguration newConfig) {
   1089         boolean ipChanged = false;
   1090         boolean proxyChanged = false;
   1091         LinkProperties linkProperties = new LinkProperties();
   1092 
   1093         switch (newConfig.ipAssignment) {
   1094             case STATIC:
   1095                 Collection<LinkAddress> currentLinkAddresses = currentConfig.linkProperties
   1096                         .getLinkAddresses();
   1097                 Collection<LinkAddress> newLinkAddresses = newConfig.linkProperties
   1098                         .getLinkAddresses();
   1099                 Collection<InetAddress> currentDnses = currentConfig.linkProperties.getDnses();
   1100                 Collection<InetAddress> newDnses = newConfig.linkProperties.getDnses();
   1101                 Collection<RouteInfo> currentRoutes = currentConfig.linkProperties.getRoutes();
   1102                 Collection<RouteInfo> newRoutes = newConfig.linkProperties.getRoutes();
   1103 
   1104                 boolean linkAddressesDiffer =
   1105                         (currentLinkAddresses.size() != newLinkAddresses.size()) ||
   1106                         !currentLinkAddresses.containsAll(newLinkAddresses);
   1107                 boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) ||
   1108                         !currentDnses.containsAll(newDnses);
   1109                 boolean routesDiffer = (currentRoutes.size() != newRoutes.size()) ||
   1110                         !currentRoutes.containsAll(newRoutes);
   1111 
   1112                 if ((currentConfig.ipAssignment != newConfig.ipAssignment) ||
   1113                         linkAddressesDiffer ||
   1114                         dnsesDiffer ||
   1115                         routesDiffer) {
   1116                     ipChanged = true;
   1117                 }
   1118                 break;
   1119             case DHCP:
   1120                 if (currentConfig.ipAssignment != newConfig.ipAssignment) {
   1121                     ipChanged = true;
   1122                 }
   1123                 break;
   1124             case UNASSIGNED:
   1125                 /* Ignore */
   1126                 break;
   1127             default:
   1128                 loge("Ignore invalid ip assignment during write");
   1129                 break;
   1130         }
   1131 
   1132         switch (newConfig.proxySettings) {
   1133             case STATIC:
   1134                 ProxyProperties newHttpProxy = newConfig.linkProperties.getHttpProxy();
   1135                 ProxyProperties currentHttpProxy = currentConfig.linkProperties.getHttpProxy();
   1136 
   1137                 if (newHttpProxy != null) {
   1138                     proxyChanged = !newHttpProxy.equals(currentHttpProxy);
   1139                 } else {
   1140                     proxyChanged = (currentHttpProxy != null);
   1141                 }
   1142                 break;
   1143             case NONE:
   1144                 if (currentConfig.proxySettings != newConfig.proxySettings) {
   1145                     proxyChanged = true;
   1146                 }
   1147                 break;
   1148             case UNASSIGNED:
   1149                 /* Ignore */
   1150                 break;
   1151             default:
   1152                 loge("Ignore invalid proxy configuration during write");
   1153                 break;
   1154         }
   1155 
   1156         if (!ipChanged) {
   1157             addIpSettingsFromConfig(linkProperties, currentConfig);
   1158         } else {
   1159             currentConfig.ipAssignment = newConfig.ipAssignment;
   1160             addIpSettingsFromConfig(linkProperties, newConfig);
   1161             log("IP config changed SSID = " + currentConfig.SSID + " linkProperties: " +
   1162                     linkProperties.toString());
   1163         }
   1164 
   1165 
   1166         if (!proxyChanged) {
   1167             linkProperties.setHttpProxy(currentConfig.linkProperties.getHttpProxy());
   1168         } else {
   1169             currentConfig.proxySettings = newConfig.proxySettings;
   1170             linkProperties.setHttpProxy(newConfig.linkProperties.getHttpProxy());
   1171             log("proxy changed SSID = " + currentConfig.SSID);
   1172             if (linkProperties.getHttpProxy() != null) {
   1173                 log(" proxyProperties: " + linkProperties.getHttpProxy().toString());
   1174             }
   1175         }
   1176 
   1177         if (ipChanged || proxyChanged) {
   1178             currentConfig.linkProperties = linkProperties;
   1179             writeIpAndProxyConfigurations();
   1180             sendConfiguredNetworksChangedBroadcast();
   1181         }
   1182         return new NetworkUpdateResult(ipChanged, proxyChanged);
   1183     }
   1184 
   1185     private static void addIpSettingsFromConfig(LinkProperties linkProperties,
   1186             WifiConfiguration config) {
   1187         for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) {
   1188             linkProperties.addLinkAddress(linkAddr);
   1189         }
   1190         for (RouteInfo route : config.linkProperties.getRoutes()) {
   1191             linkProperties.addRoute(route);
   1192         }
   1193         for (InetAddress dns : config.linkProperties.getDnses()) {
   1194             linkProperties.addDns(dns);
   1195         }
   1196     }
   1197 
   1198     /**
   1199      * Read the variables from the supplicant daemon that are needed to
   1200      * fill in the WifiConfiguration object.
   1201      *
   1202      * @param config the {@link WifiConfiguration} object to be filled in.
   1203      */
   1204     private static void readNetworkVariables(WifiConfiguration config) {
   1205 
   1206         int netId = config.networkId;
   1207         if (netId < 0)
   1208             return;
   1209 
   1210         /*
   1211          * TODO: maybe should have a native method that takes an array of
   1212          * variable names and returns an array of values. But we'd still
   1213          * be doing a round trip to the supplicant daemon for each variable.
   1214          */
   1215         String value;
   1216 
   1217         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName);
   1218         if (!TextUtils.isEmpty(value)) {
   1219             config.SSID = value;
   1220         } else {
   1221             config.SSID = null;
   1222         }
   1223 
   1224         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName);
   1225         if (!TextUtils.isEmpty(value)) {
   1226             config.BSSID = value;
   1227         } else {
   1228             config.BSSID = null;
   1229         }
   1230 
   1231         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName);
   1232         config.priority = -1;
   1233         if (!TextUtils.isEmpty(value)) {
   1234             try {
   1235                 config.priority = Integer.parseInt(value);
   1236             } catch (NumberFormatException ignore) {
   1237             }
   1238         }
   1239 
   1240         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName);
   1241         config.hiddenSSID = false;
   1242         if (!TextUtils.isEmpty(value)) {
   1243             try {
   1244                 config.hiddenSSID = Integer.parseInt(value) != 0;
   1245             } catch (NumberFormatException ignore) {
   1246             }
   1247         }
   1248 
   1249         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName);
   1250         config.wepTxKeyIndex = -1;
   1251         if (!TextUtils.isEmpty(value)) {
   1252             try {
   1253                 config.wepTxKeyIndex = Integer.parseInt(value);
   1254             } catch (NumberFormatException ignore) {
   1255             }
   1256         }
   1257 
   1258         for (int i = 0; i < 4; i++) {
   1259             value = WifiNative.getNetworkVariableCommand(netId,
   1260                     WifiConfiguration.wepKeyVarNames[i]);
   1261             if (!TextUtils.isEmpty(value)) {
   1262                 config.wepKeys[i] = value;
   1263             } else {
   1264                 config.wepKeys[i] = null;
   1265             }
   1266         }
   1267 
   1268         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName);
   1269         if (!TextUtils.isEmpty(value)) {
   1270             config.preSharedKey = value;
   1271         } else {
   1272             config.preSharedKey = null;
   1273         }
   1274 
   1275         value = WifiNative.getNetworkVariableCommand(config.networkId,
   1276                 WifiConfiguration.Protocol.varName);
   1277         if (!TextUtils.isEmpty(value)) {
   1278             String vals[] = value.split(" ");
   1279             for (String val : vals) {
   1280                 int index =
   1281                     lookupString(val, WifiConfiguration.Protocol.strings);
   1282                 if (0 <= index) {
   1283                     config.allowedProtocols.set(index);
   1284                 }
   1285             }
   1286         }
   1287 
   1288         value = WifiNative.getNetworkVariableCommand(config.networkId,
   1289                 WifiConfiguration.KeyMgmt.varName);
   1290         if (!TextUtils.isEmpty(value)) {
   1291             String vals[] = value.split(" ");
   1292             for (String val : vals) {
   1293                 int index =
   1294                     lookupString(val, WifiConfiguration.KeyMgmt.strings);
   1295                 if (0 <= index) {
   1296                     config.allowedKeyManagement.set(index);
   1297                 }
   1298             }
   1299         }
   1300 
   1301         value = WifiNative.getNetworkVariableCommand(config.networkId,
   1302                 WifiConfiguration.AuthAlgorithm.varName);
   1303         if (!TextUtils.isEmpty(value)) {
   1304             String vals[] = value.split(" ");
   1305             for (String val : vals) {
   1306                 int index =
   1307                     lookupString(val, WifiConfiguration.AuthAlgorithm.strings);
   1308                 if (0 <= index) {
   1309                     config.allowedAuthAlgorithms.set(index);
   1310                 }
   1311             }
   1312         }
   1313 
   1314         value = WifiNative.getNetworkVariableCommand(config.networkId,
   1315                 WifiConfiguration.PairwiseCipher.varName);
   1316         if (!TextUtils.isEmpty(value)) {
   1317             String vals[] = value.split(" ");
   1318             for (String val : vals) {
   1319                 int index =
   1320                     lookupString(val, WifiConfiguration.PairwiseCipher.strings);
   1321                 if (0 <= index) {
   1322                     config.allowedPairwiseCiphers.set(index);
   1323                 }
   1324             }
   1325         }
   1326 
   1327         value = WifiNative.getNetworkVariableCommand(config.networkId,
   1328                 WifiConfiguration.GroupCipher.varName);
   1329         if (!TextUtils.isEmpty(value)) {
   1330             String vals[] = value.split(" ");
   1331             for (String val : vals) {
   1332                 int index =
   1333                     lookupString(val, WifiConfiguration.GroupCipher.strings);
   1334                 if (0 <= index) {
   1335                     config.allowedGroupCiphers.set(index);
   1336                 }
   1337             }
   1338         }
   1339 
   1340         for (WifiConfiguration.EnterpriseField field :
   1341                 config.enterpriseFields) {
   1342             value = WifiNative.getNetworkVariableCommand(netId,
   1343                     field.varName());
   1344             if (!TextUtils.isEmpty(value)) {
   1345                 if (field != config.eap) value = removeDoubleQuotes(value);
   1346                 field.setValue(value);
   1347             }
   1348         }
   1349     }
   1350 
   1351     private static String removeDoubleQuotes(String string) {
   1352         if (string.length() <= 2) return "";
   1353         return string.substring(1, string.length() - 1);
   1354     }
   1355 
   1356     private static String convertToQuotedString(String string) {
   1357         return "\"" + string + "\"";
   1358     }
   1359 
   1360     private static String makeString(BitSet set, String[] strings) {
   1361         StringBuffer buf = new StringBuffer();
   1362         int nextSetBit = -1;
   1363 
   1364         /* Make sure all set bits are in [0, strings.length) to avoid
   1365          * going out of bounds on strings.  (Shouldn't happen, but...) */
   1366         set = set.get(0, strings.length);
   1367 
   1368         while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
   1369             buf.append(strings[nextSetBit].replace('_', '-')).append(' ');
   1370         }
   1371 
   1372         // remove trailing space
   1373         if (set.cardinality() > 0) {
   1374             buf.setLength(buf.length() - 1);
   1375         }
   1376 
   1377         return buf.toString();
   1378     }
   1379 
   1380     private static int lookupString(String string, String[] strings) {
   1381         int size = strings.length;
   1382 
   1383         string = string.replace('-', '_');
   1384 
   1385         for (int i = 0; i < size; i++)
   1386             if (string.equals(strings[i]))
   1387                 return i;
   1388 
   1389         // if we ever get here, we should probably add the
   1390         // value to WifiConfiguration to reflect that it's
   1391         // supported by the WPA supplicant
   1392         loge("Failed to look-up a string: " + string);
   1393 
   1394         return -1;
   1395     }
   1396 
   1397     /* Returns a unique for a given configuration */
   1398     private static int configKey(WifiConfiguration config) {
   1399         String key;
   1400 
   1401         if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
   1402             key = config.SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
   1403         } else if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
   1404                 config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
   1405             key = config.SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
   1406         } else if (config.wepKeys[0] != null) {
   1407             key = config.SSID + "WEP";
   1408         } else {
   1409             key = config.SSID + KeyMgmt.strings[KeyMgmt.NONE];
   1410         }
   1411 
   1412         return key.hashCode();
   1413     }
   1414 
   1415     static String dump() {
   1416         StringBuffer sb = new StringBuffer();
   1417         String LS = System.getProperty("line.separator");
   1418         sb.append("sLastPriority ").append(sLastPriority).append(LS);
   1419         sb.append("Configured networks ").append(LS);
   1420         for (WifiConfiguration conf : getConfiguredNetworks()) {
   1421             sb.append(conf).append(LS);
   1422         }
   1423         return sb.toString();
   1424     }
   1425 
   1426     public static String getConfigFile() {
   1427         return ipConfigFile;
   1428     }
   1429 
   1430     private static void loge(String s) {
   1431         Log.e(TAG, s);
   1432     }
   1433 
   1434     private static void log(String s) {
   1435         Log.d(TAG, s);
   1436     }
   1437 }
   1438