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