177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistpackage com.android.server.wifi.hotspot2;
277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
38ca4ac971a9b862fbd69c57af3a3c0029a6b9f4dPeter Qiuimport static com.android.server.wifi.hotspot2.anqp.Constants.BYTES_IN_EUI48;
48ca4ac971a9b862fbd69c57af3a3c0029a6b9f4dPeter Qiuimport static com.android.server.wifi.hotspot2.anqp.Constants.BYTE_MASK;
5947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne
677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport android.net.wifi.ScanResult;
773185809f4a44a8ee272afe3e5253496aeb966ceLorenzo Colittiimport android.util.Log;
877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
98ca4ac971a9b862fbd69c57af3a3c0029a6b9f4dPeter Qiuimport com.android.server.wifi.hotspot2.anqp.ANQPElement;
108ca4ac971a9b862fbd69c57af3a3c0029a6b9f4dPeter Qiuimport com.android.server.wifi.hotspot2.anqp.Constants;
118ca4ac971a9b862fbd69c57af3a3c0029a6b9f4dPeter Qiuimport com.android.server.wifi.hotspot2.anqp.RawByteElement;
125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport com.android.server.wifi.util.InformationElementUtil;
1377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
14a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvistimport java.nio.BufferUnderflowException;
1577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.nio.ByteBuffer;
16fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvistimport java.nio.CharBuffer;
17fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvistimport java.nio.charset.CharacterCodingException;
18fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvistimport java.nio.charset.CharsetDecoder;
1977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.nio.charset.StandardCharsets;
20f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhneimport java.util.ArrayList;
2177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.List;
2277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.Map;
2373185809f4a44a8ee272afe3e5253496aeb966ceLorenzo Colitti
2477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistpublic class NetworkDetail {
2577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
268f14e9784bd8ca8e832fff86597a28755f7e668eSamuel Tan    private static final boolean DBG = false;
275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills
28243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private static final String TAG = "NetworkDetail:";
2977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
3077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public enum Ant {
3177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Private,
3277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        PrivateWithGuest,
3377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        ChargeablePublic,
3477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        FreePublic,
3577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Personal,
3677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        EmergencyOnly,
3777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd6,
3877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd7,
3977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd8,
4077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd9,
4177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd10,
4277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd11,
4377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd12,
4477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd13,
4577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        TestOrExperimental,
4677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Wildcard
4777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
4877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
4977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public enum HSRelease {
5077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        R1,
5177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        R2,
5277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Unknown
5377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
5477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
5577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // General identifiers:
5677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final String mSSID;
5777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final long mHESSID;
5877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final long mBSSID;
5959f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    // True if the SSID is potentially from a hidden network
6059f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    private final boolean mIsHiddenSsid;
6177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
6277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // BSS Load element:
6377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final int mStationCount;
6477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final int mChannelUtilization;
6577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final int mCapacity;
6677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
67243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    //channel detailed information
68243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe   /*
69243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    * 0 -- 20 MHz
70243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    * 1 -- 40 MHz
71243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    * 2 -- 80 MHz
72243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    * 3 -- 160 MHz
73243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    * 4 -- 80 + 80 MHz
74243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    */
75243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private final int mChannelWidth;
76243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private final int mPrimaryFreq;
77243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private final int mCenterfreq0;
78243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private final int mCenterfreq1;
79f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne
80f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne    /*
81f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne     * 802.11 Standard (calculated from Capabilities and Supported Rates)
82f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne     * 0 -- Unknown
83f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne     * 1 -- 802.11a
84f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne     * 2 -- 802.11b
85f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne     * 3 -- 802.11g
86f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne     * 4 -- 802.11n
87f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne     * 7 -- 802.11ac
88f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne     */
89f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne    private final int mWifiMode;
90f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne    private final int mMaxRate;
91f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne
9277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    /*
9377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * From Interworking element:
9477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * mAnt non null indicates the presence of Interworking, i.e. 802.11u
9577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     */
9677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final Ant mAnt;
9777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final boolean mInternet;
9877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
9977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    /*
10077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * From HS20 Indication element:
10177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * mHSRelease is null only if the HS20 Indication element was not present.
10277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * mAnqpDomainID is set to -1 if not present in the element.
10377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     */
10477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final HSRelease mHSRelease;
10577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final int mAnqpDomainID;
10677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
10777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    /*
10877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * From beacon:
10977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * mAnqpOICount is how many additional OIs are available through ANQP.
11077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * mRoamingConsortiums is either null, if the element was not present, or is an array of
11177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * 1, 2 or 3 longs in which the roaming consortium values occupy the LSBs.
11277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     */
11377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final int mAnqpOICount;
11477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final long[] mRoamingConsortiums;
115947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne    private int mDtimInterval = -1;
11677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills    private final InformationElementUtil.ExtendedCapabilities mExtendedCapabilities;
11877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
11977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final Map<Constants.ANQPElementType, ANQPElement> mANQPElements;
12077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills    public NetworkDetail(String bssid, ScanResult.InformationElement[] infoElements,
1225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills            List<String> anqpLines, int freq) {
12377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (infoElements == null) {
1245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills            throw new IllegalArgumentException("Null information elements");
12577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
12677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1275bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist        mBSSID = Utils.parseMac(bssid);
12877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
12977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        String ssid = null;
13059f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        boolean isHiddenSsid = false;
13177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        byte[] ssidOctets = null;
13277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        InformationElementUtil.BssLoad bssLoad = new InformationElementUtil.BssLoad();
13477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        InformationElementUtil.Interworking interworking =
1365d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                new InformationElementUtil.Interworking();
13777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        InformationElementUtil.RoamingConsortium roamingConsortium =
1395d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                new InformationElementUtil.RoamingConsortium();
14077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa();
14277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1435d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        InformationElementUtil.HtOperation htOperation = new InformationElementUtil.HtOperation();
1445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        InformationElementUtil.VhtOperation vhtOperation =
1455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                new InformationElementUtil.VhtOperation();
1465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills
1475d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        InformationElementUtil.ExtendedCapabilities extendedCapabilities =
1485d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                new InformationElementUtil.ExtendedCapabilities();
149243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
150947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne        InformationElementUtil.TrafficIndicationMap trafficIndicationMap =
151947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne                new InformationElementUtil.TrafficIndicationMap();
152f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne
153f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        InformationElementUtil.SupportedRates supportedRates =
154f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                new InformationElementUtil.SupportedRates();
155f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        InformationElementUtil.SupportedRates extendedSupportedRates =
156f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                new InformationElementUtil.SupportedRates();
157f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne
158c1072acda7dc8b9d7bc4a9bb0b1177b14ecaf276xinhe        RuntimeException exception = null;
159f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne
160f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        ArrayList<Integer> iesFound = new ArrayList<Integer>();
161fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        try {
1625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills            for (ScanResult.InformationElement ie : infoElements) {
163f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                iesFound.add(ie.id);
1645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                switch (ie.id) {
1655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                    case ScanResult.InformationElement.EID_SSID:
1665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                        ssidOctets = ie.bytes;
167fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
1685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                    case ScanResult.InformationElement.EID_BSS_LOAD:
1695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                        bssLoad.from(ie);
170fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
1715d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                    case ScanResult.InformationElement.EID_HT_OPERATION:
1725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                        htOperation.from(ie);
173fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
1745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                    case ScanResult.InformationElement.EID_VHT_OPERATION:
1755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                        vhtOperation.from(ie);
176fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
1775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                    case ScanResult.InformationElement.EID_INTERWORKING:
1785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                        interworking.from(ie);
179fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
1805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                    case ScanResult.InformationElement.EID_ROAMING_CONSORTIUM:
1815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                        roamingConsortium.from(ie);
182fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
1835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                    case ScanResult.InformationElement.EID_VSA:
1845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                        vsa.from(ie);
185fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
1865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                    case ScanResult.InformationElement.EID_EXTENDED_CAPS:
1875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                        extendedCapabilities.from(ie);
188fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
189947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne                    case ScanResult.InformationElement.EID_TIM:
190947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne                        trafficIndicationMap.from(ie);
191947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne                        break;
192f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    case ScanResult.InformationElement.EID_SUPPORTED_RATES:
193f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                        supportedRates.from(ie);
194f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                        break;
195f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    case ScanResult.InformationElement.EID_EXTENDED_SUPPORTED_RATES:
196f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                        extendedSupportedRates.from(ie);
197f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                        break;
198fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    default:
199243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                        break;
200fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                }
201fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist            }
202fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        }
203be24c9af85b8a6e02b24582418a4608e14396f2aJan Nordqvist        catch (IllegalArgumentException | BufferUnderflowException | ArrayIndexOutOfBoundsException e) {
2041c03d75c73b9f5fa24a795a0d546f4f56b82ab9bJan Nordqvist            Log.d(Utils.hs2LogTag(getClass()), "Caught " + e);
205fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist            if (ssidOctets == null) {
206d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist                throw new IllegalArgumentException("Malformed IE string (no SSID)", e);
20777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
208a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist            exception = e;
20977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
21077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (ssidOctets != null) {
211d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist            /*
212d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist             * Strict use of the "UTF-8 SSID" bit by APs appears to be spotty at best even if the
213d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist             * encoding truly is in UTF-8. An unconditional attempt to decode the SSID as UTF-8 is
214d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist             * therefore always made with a fall back to 8859-1 under normal circumstances.
215d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist             * If, however, a previous exception was detected and the UTF-8 bit is set, failure to
216d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist             * decode the SSID will be used as an indication that the whole frame is malformed and
217d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist             * an exception will be triggered.
218d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist             */
219d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist            CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
220d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist            try {
221d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist                CharBuffer decoded = decoder.decode(ByteBuffer.wrap(ssidOctets));
222d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist                ssid = decoded.toString();
22377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
224d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist            catch (CharacterCodingException cce) {
225d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist                ssid = null;
22677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
227fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
228d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist            if (ssid == null) {
2295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                if (extendedCapabilities.isStrictUtf8() && exception != null) {
230d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist                    throw new IllegalArgumentException("Failed to decode SSID in dubious IE string");
231fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                }
232d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist                else {
233d33dc0d01f16ef7c338c3e3c82eaefa9e914ff83Jan Nordqvist                    ssid = new String(ssidOctets, StandardCharsets.ISO_8859_1);
234fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                }
235fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist            }
23659f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne            isHiddenSsid = true;
23759f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne            for (byte byteVal : ssidOctets) {
23859f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne                if (byteVal != 0) {
23959f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne                    isHiddenSsid = false;
24059f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne                    break;
24159f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne                }
24259f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne            }
24377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
24477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
24577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mSSID = ssid;
2465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mHESSID = interworking.hessid;
24759f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        mIsHiddenSsid = isHiddenSsid;
2485d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mStationCount = bssLoad.stationCount;
2495d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mChannelUtilization = bssLoad.channelUtilization;
2505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mCapacity = bssLoad.capacity;
2515d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mAnt = interworking.ant;
2525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mInternet = interworking.internet;
2535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mHSRelease = vsa.hsRelease;
2545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mAnqpDomainID = vsa.anqpDomainID;
2555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mAnqpOICount = roamingConsortium.anqpOICount;
2562e889dc0b3f348f45cc5f5006d8784bed30583a9Masashi Honma        mRoamingConsortiums = roamingConsortium.getRoamingConsortiums();
25777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mExtendedCapabilities = extendedCapabilities;
25865d8ba5dd551cd132789e8feb270dfc7998dfbdcRoshan Pius        mANQPElements = null;
259243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        //set up channel info
260243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mPrimaryFreq = freq;
261243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
2625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        if (vhtOperation.isValid()) {
263243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            // 80 or 160 MHz
2645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills            mChannelWidth = vhtOperation.getChannelWidth();
2655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills            mCenterfreq0 = vhtOperation.getCenterFreq0();
2665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills            mCenterfreq1 = vhtOperation.getCenterFreq1();
267243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        } else {
2685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills            mChannelWidth = htOperation.getChannelWidth();
2695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills            mCenterfreq0 = htOperation.getCenterFreq0(mPrimaryFreq);
2705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills            mCenterfreq1  = 0;
271243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        }
272947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne
273947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne        // If trafficIndicationMap is not valid, mDtimPeriod will be negative
27459f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        if (trafficIndicationMap.isValid()) {
27559f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne            mDtimInterval = trafficIndicationMap.mDtimPeriod;
27659f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        }
277947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne
278f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        int maxRateA = 0;
279f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        int maxRateB = 0;
280f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        // If we got some Extended supported rates, consider them, if not default to 0
281f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        if (extendedSupportedRates.isValid()) {
282f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne            // rates are sorted from smallest to largest in InformationElement
283f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne            maxRateB = extendedSupportedRates.mRates.get(extendedSupportedRates.mRates.size() - 1);
284f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        }
285f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        // Only process the determination logic if we got a 'SupportedRates'
286f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        if (supportedRates.isValid()) {
287f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne            maxRateA = supportedRates.mRates.get(supportedRates.mRates.size() - 1);
288f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne            mMaxRate = maxRateA > maxRateB ? maxRateA : maxRateB;
289f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne            mWifiMode = InformationElementUtil.WifiMode.determineMode(mPrimaryFreq, mMaxRate,
290f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    vhtOperation.isValid(),
291f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    iesFound.contains(ScanResult.InformationElement.EID_HT_OPERATION),
292f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    iesFound.contains(ScanResult.InformationElement.EID_ERP));
293f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        } else {
294f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne            mWifiMode = 0;
295f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne            mMaxRate = 0;
296f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        }
2978f14e9784bd8ca8e832fff86597a28755f7e668eSamuel Tan        if (DBG) {
298f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne            Log.d(TAG, mSSID + "ChannelWidth is: " + mChannelWidth + " PrimaryFreq: " + mPrimaryFreq
299f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + " mCenterfreq0: " + mCenterfreq0 + " mCenterfreq1: " + mCenterfreq1
300b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu                    + (extendedCapabilities.is80211McRTTResponder() ? "Support RTT responder"
301f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    : "Do not support RTT responder"));
302f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne            Log.v("WifiMode", mSSID
303f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", WifiMode: " + InformationElementUtil.WifiMode.toString(mWifiMode)
304f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", Freq: " + mPrimaryFreq
305f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", mMaxRate: " + mMaxRate
306f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", VHT: " + String.valueOf(vhtOperation.isValid())
307f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", HT: " + String.valueOf(
308f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    iesFound.contains(ScanResult.InformationElement.EID_HT_OPERATION))
309f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", ERP: " + String.valueOf(
310f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    iesFound.contains(ScanResult.InformationElement.EID_ERP))
311f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", SupportedRates: " + supportedRates.toString()
312f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + " ExtendedSupportedRates: " + extendedSupportedRates.toString());
313d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        }
31477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
31577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
316fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist    private static ByteBuffer getAndAdvancePayload(ByteBuffer data, int plLength) {
317398823d45a240ff90ff2ffab3ff4a8b8646f24c9Jan Nordqvist        ByteBuffer payload = data.duplicate().order(data.order());
318fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        payload.limit(payload.position() + plLength);
319fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        data.position(data.position() + plLength);
320fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        return payload;
321fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist    }
322fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
32377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private NetworkDetail(NetworkDetail base, Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
32477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mSSID = base.mSSID;
32559f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        mIsHiddenSsid = base.mIsHiddenSsid;
32677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mBSSID = base.mBSSID;
32777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mHESSID = base.mHESSID;
32877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mStationCount = base.mStationCount;
32977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mChannelUtilization = base.mChannelUtilization;
33077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mCapacity = base.mCapacity;
33177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnt = base.mAnt;
33277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mInternet = base.mInternet;
33377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mHSRelease = base.mHSRelease;
33477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnqpDomainID = base.mAnqpDomainID;
33577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnqpOICount = base.mAnqpOICount;
33677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mRoamingConsortiums = base.mRoamingConsortiums;
3375d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mExtendedCapabilities =
3385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                new InformationElementUtil.ExtendedCapabilities(base.mExtendedCapabilities);
33977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mANQPElements = anqpElements;
340243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mChannelWidth = base.mChannelWidth;
341243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mPrimaryFreq = base.mPrimaryFreq;
342243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mCenterfreq0 = base.mCenterfreq0;
343243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mCenterfreq1 = base.mCenterfreq1;
344947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne        mDtimInterval = base.mDtimInterval;
345f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        mWifiMode = base.mWifiMode;
346f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        mMaxRate = base.mMaxRate;
34777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
34877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
34977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public NetworkDetail complete(Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
35077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return new NetworkDetail(this, anqpElements);
35177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
35277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
3531d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist    public boolean queriable(List<Constants.ANQPElementType> queryElements) {
3541d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        return mAnt != null &&
3551d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist                (Constants.hasBaseANQPElements(queryElements) ||
3561d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist                 Constants.hasR2Elements(queryElements) && mHSRelease == HSRelease.R2);
35777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
35877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
35977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean has80211uInfo() {
36077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnt != null || mRoamingConsortiums != null || mHSRelease != null;
36177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
36277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
36377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean hasInterworking() {
36477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnt != null;
36577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
36677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
36777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String getSSID() {
36877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mSSID;
36977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
37077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
3719a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist    public String getTrimmedSSID() {
372c5d349d814e5eeb72beb62d722699a9624fb9932Julia Reynolds        if (mSSID != null) {
373c5d349d814e5eeb72beb62d722699a9624fb9932Julia Reynolds            for (int n = 0; n < mSSID.length(); n++) {
374c5d349d814e5eeb72beb62d722699a9624fb9932Julia Reynolds                if (mSSID.charAt(n) != 0) {
375c5d349d814e5eeb72beb62d722699a9624fb9932Julia Reynolds                    return mSSID;
376c5d349d814e5eeb72beb62d722699a9624fb9932Julia Reynolds                }
3779a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist            }
3789a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist        }
3799a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist        return "";
3809a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist    }
3819a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist
38277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public long getHESSID() {
38377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mHESSID;
38477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
38577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
38677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public long getBSSID() {
38777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mBSSID;
38877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
38977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
39077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getStationCount() {
39177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mStationCount;
39277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
39377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
39477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getChannelUtilization() {
39577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mChannelUtilization;
39677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
39777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
39877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getCapacity() {
39977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mCapacity;
40077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
40177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
40277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean isInterworking() {
40377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnt != null;
40477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
40577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
40677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public Ant getAnt() {
40777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnt;
40877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
40977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
41077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean isInternet() {
41177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mInternet;
41277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
41377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
41477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public HSRelease getHSRelease() {
41577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mHSRelease;
41677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
41777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
41877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getAnqpDomainID() {
41977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnqpDomainID;
42077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
42177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
4222e814680f4dd27a5f825afab189843582235cedcJan Nordqvist    public byte[] getOsuProviders() {
4232e814680f4dd27a5f825afab189843582235cedcJan Nordqvist        if (mANQPElements == null) {
4242e814680f4dd27a5f825afab189843582235cedcJan Nordqvist            return null;
4252e814680f4dd27a5f825afab189843582235cedcJan Nordqvist        }
4262e814680f4dd27a5f825afab189843582235cedcJan Nordqvist        ANQPElement osuProviders = mANQPElements.get(Constants.ANQPElementType.HSOSUProviders);
4272e814680f4dd27a5f825afab189843582235cedcJan Nordqvist        return osuProviders != null ? ((RawByteElement) osuProviders).getPayload() : null;
4282e814680f4dd27a5f825afab189843582235cedcJan Nordqvist    }
4292e814680f4dd27a5f825afab189843582235cedcJan Nordqvist
43077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getAnqpOICount() {
43177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnqpOICount;
43277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
43377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
43477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public long[] getRoamingConsortiums() {
43577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mRoamingConsortiums;
43677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
43777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
43877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public Map<Constants.ANQPElementType, ANQPElement> getANQPElements() {
43977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mANQPElements;
44077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
44177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
442243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public int getChannelWidth() {
443243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        return mChannelWidth;
444243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
445243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
446243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public int getCenterfreq0() {
447243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        return mCenterfreq0;
448243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
449243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
450243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public int getCenterfreq1() {
451243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        return mCenterfreq1;
452243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
453243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
454f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne    public int getWifiMode() {
455f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        return mWifiMode;
456f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne    }
457f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne
458947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne    public int getDtimInterval() {
459947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne        return mDtimInterval;
460947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne    }
461947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne
462243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public boolean is80211McResponderSupport() {
463b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu        return mExtendedCapabilities.is80211McRTTResponder();
464243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
465243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
46677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean isSSID_UTF8() {
4675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        return mExtendedCapabilities.isStrictUtf8();
46877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
46977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
47077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    @Override
47177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean equals(Object thatObject) {
47277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (this == thatObject) {
47377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return true;
47477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
47577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (thatObject == null || getClass() != thatObject.getClass()) {
47677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return false;
47777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
47877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
47977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        NetworkDetail that = (NetworkDetail)thatObject;
48077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
48177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return getSSID().equals(that.getSSID()) && getBSSID() == that.getBSSID();
48277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
48377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
48477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    @Override
48577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int hashCode() {
48677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return ((mSSID.hashCode() * 31) + (int)(mBSSID >>> 32)) * 31 + (int)mBSSID;
48777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
48877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
48977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    @Override
49077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String toString() {
4911d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        return String.format("NetworkInfo{SSID='%s', HESSID=%x, BSSID=%x, StationCount=%d, " +
4921d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist                "ChannelUtilization=%d, Capacity=%d, Ant=%s, Internet=%s, " +
493e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan                "HSRelease=%s, AnqpDomainID=%d, " +
4941d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist                "AnqpOICount=%d, RoamingConsortiums=%s}",
49577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mSSID, mHESSID, mBSSID, mStationCount,
49677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mChannelUtilization, mCapacity, mAnt, mInternet,
497e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan                mHSRelease, mAnqpDomainID,
49877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mAnqpOICount, Utils.roamingConsortiumsToString(mRoamingConsortiums));
49977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
50077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
50177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String toKeyString() {
502a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        return mHESSID != 0 ?
503866c5b061e6e762f2627e3467afc0fe6f29c2668Jan Nordqvist            String.format("'%s':%012x (%012x)", mSSID, mBSSID, mHESSID) :
504866c5b061e6e762f2627e3467afc0fe6f29c2668Jan Nordqvist            String.format("'%s':%012x", mSSID, mBSSID);
50577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
50677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
50777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String getBSSIDString() {
50877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return toMACString(mBSSID);
50977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
51077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
51159f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    /**
51259f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * Evaluates the ScanResult this NetworkDetail is built from
51359f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * returns true if built from a Beacon Frame
51459f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * returns false if built from a Probe Response
51559f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     */
51659f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    public boolean isBeaconFrame() {
51759f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        // Beacon frames have a 'Traffic Indication Map' Information element
51859f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        // Probe Responses do not. This is indicated by a DTIM period > 0
51959f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        return mDtimInterval > 0;
52059f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    }
52159f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne
52259f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    /**
52359f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * Evaluates the ScanResult this NetworkDetail is built from
52459f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * returns true if built from a hidden Beacon Frame
52559f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * returns false if not hidden or not a Beacon
52659f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     */
52759f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    public boolean isHiddenBeaconFrame() {
52859f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        // Hidden networks are not 80211 standard, but it is common for a hidden network beacon
52959f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        // frame to either send zero-value bytes as the SSID, or to send no bytes at all.
53059f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        return isBeaconFrame() && mIsHiddenSsid;
53159f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    }
53259f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne
533ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    public static String toMACString(long mac) {
53477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        StringBuilder sb = new StringBuilder();
53577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        boolean first = true;
53677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        for (int n = BYTES_IN_EUI48 - 1; n >= 0; n--) {
53777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (first) {
53877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                first = false;
53977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            } else {
54077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                sb.append(':');
54177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
54277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            sb.append(String.format("%02x", (mac >>> (n * Byte.SIZE)) & BYTE_MASK));
54377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
54477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return sb.toString();
54577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
54677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist}
547