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