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