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;
2565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mRoamingConsortiums = roamingConsortium.roamingConsortiums;
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            Log.w("WifiMode", mSSID + ", Invalid SupportedRates!!!");
297f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        }
2988f14e9784bd8ca8e832fff86597a28755f7e668eSamuel Tan        if (DBG) {
299f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne            Log.d(TAG, mSSID + "ChannelWidth is: " + mChannelWidth + " PrimaryFreq: " + mPrimaryFreq
300f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + " mCenterfreq0: " + mCenterfreq0 + " mCenterfreq1: " + mCenterfreq1
301b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu                    + (extendedCapabilities.is80211McRTTResponder() ? "Support RTT responder"
302f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    : "Do not support RTT responder"));
303f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne            Log.v("WifiMode", mSSID
304f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", WifiMode: " + InformationElementUtil.WifiMode.toString(mWifiMode)
305f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", Freq: " + mPrimaryFreq
306f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", mMaxRate: " + mMaxRate
307f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", VHT: " + String.valueOf(vhtOperation.isValid())
308f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", HT: " + String.valueOf(
309f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    iesFound.contains(ScanResult.InformationElement.EID_HT_OPERATION))
310f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", ERP: " + String.valueOf(
311f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    iesFound.contains(ScanResult.InformationElement.EID_ERP))
312f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + ", SupportedRates: " + supportedRates.toString()
313f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne                    + " ExtendedSupportedRates: " + extendedSupportedRates.toString());
314d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        }
31577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
31677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
317fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist    private static ByteBuffer getAndAdvancePayload(ByteBuffer data, int plLength) {
318398823d45a240ff90ff2ffab3ff4a8b8646f24c9Jan Nordqvist        ByteBuffer payload = data.duplicate().order(data.order());
319fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        payload.limit(payload.position() + plLength);
320fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        data.position(data.position() + plLength);
321fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        return payload;
322fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist    }
323fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
32477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private NetworkDetail(NetworkDetail base, Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
32577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mSSID = base.mSSID;
32659f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        mIsHiddenSsid = base.mIsHiddenSsid;
32777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mBSSID = base.mBSSID;
32877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mHESSID = base.mHESSID;
32977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mStationCount = base.mStationCount;
33077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mChannelUtilization = base.mChannelUtilization;
33177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mCapacity = base.mCapacity;
33277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnt = base.mAnt;
33377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mInternet = base.mInternet;
33477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mHSRelease = base.mHSRelease;
33577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnqpDomainID = base.mAnqpDomainID;
33677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnqpOICount = base.mAnqpOICount;
33777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mRoamingConsortiums = base.mRoamingConsortiums;
3385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        mExtendedCapabilities =
3395d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills                new InformationElementUtil.ExtendedCapabilities(base.mExtendedCapabilities);
34077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mANQPElements = anqpElements;
341243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mChannelWidth = base.mChannelWidth;
342243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mPrimaryFreq = base.mPrimaryFreq;
343243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mCenterfreq0 = base.mCenterfreq0;
344243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mCenterfreq1 = base.mCenterfreq1;
345947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne        mDtimInterval = base.mDtimInterval;
346f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        mWifiMode = base.mWifiMode;
347f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        mMaxRate = base.mMaxRate;
34877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
34977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
35077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public NetworkDetail complete(Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
35177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return new NetworkDetail(this, anqpElements);
35277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
35377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
3541d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist    public boolean queriable(List<Constants.ANQPElementType> queryElements) {
3551d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        return mAnt != null &&
3561d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist                (Constants.hasBaseANQPElements(queryElements) ||
3571d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist                 Constants.hasR2Elements(queryElements) && mHSRelease == HSRelease.R2);
35877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
35977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
36077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean has80211uInfo() {
36177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnt != null || mRoamingConsortiums != null || mHSRelease != null;
36277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
36377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
36477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean hasInterworking() {
36577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnt != null;
36677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
36777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
36877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String getSSID() {
36977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mSSID;
37077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
37177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
3729a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist    public String getTrimmedSSID() {
373c5d349d814e5eeb72beb62d722699a9624fb9932Julia Reynolds        if (mSSID != null) {
374c5d349d814e5eeb72beb62d722699a9624fb9932Julia Reynolds            for (int n = 0; n < mSSID.length(); n++) {
375c5d349d814e5eeb72beb62d722699a9624fb9932Julia Reynolds                if (mSSID.charAt(n) != 0) {
376c5d349d814e5eeb72beb62d722699a9624fb9932Julia Reynolds                    return mSSID;
377c5d349d814e5eeb72beb62d722699a9624fb9932Julia Reynolds                }
3789a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist            }
3799a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist        }
3809a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist        return "";
3819a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist    }
3829a64375bfb3431ef8d4ec1f2e97349c106c9c5f0Jan Nordqvist
38377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public long getHESSID() {
38477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mHESSID;
38577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
38677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
38777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public long getBSSID() {
38877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mBSSID;
38977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
39077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
39177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getStationCount() {
39277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mStationCount;
39377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
39477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
39577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getChannelUtilization() {
39677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mChannelUtilization;
39777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
39877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
39977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getCapacity() {
40077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mCapacity;
40177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
40277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
40377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean isInterworking() {
40477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnt != null;
40577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
40677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
40777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public Ant getAnt() {
40877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnt;
40977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
41077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
41177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean isInternet() {
41277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mInternet;
41377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
41477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
41577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public HSRelease getHSRelease() {
41677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mHSRelease;
41777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
41877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
41977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getAnqpDomainID() {
42077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnqpDomainID;
42177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
42277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
4232e814680f4dd27a5f825afab189843582235cedcJan Nordqvist    public byte[] getOsuProviders() {
4242e814680f4dd27a5f825afab189843582235cedcJan Nordqvist        if (mANQPElements == null) {
4252e814680f4dd27a5f825afab189843582235cedcJan Nordqvist            return null;
4262e814680f4dd27a5f825afab189843582235cedcJan Nordqvist        }
4272e814680f4dd27a5f825afab189843582235cedcJan Nordqvist        ANQPElement osuProviders = mANQPElements.get(Constants.ANQPElementType.HSOSUProviders);
4282e814680f4dd27a5f825afab189843582235cedcJan Nordqvist        return osuProviders != null ? ((RawByteElement) osuProviders).getPayload() : null;
4292e814680f4dd27a5f825afab189843582235cedcJan Nordqvist    }
4302e814680f4dd27a5f825afab189843582235cedcJan Nordqvist
43177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getAnqpOICount() {
43277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnqpOICount;
43377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
43477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
43577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public long[] getRoamingConsortiums() {
43677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mRoamingConsortiums;
43777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
43877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
43977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public Map<Constants.ANQPElementType, ANQPElement> getANQPElements() {
44077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mANQPElements;
44177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
44277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
443243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public int getChannelWidth() {
444243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        return mChannelWidth;
445243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
446243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
447243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public int getCenterfreq0() {
448243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        return mCenterfreq0;
449243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
450243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
451243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public int getCenterfreq1() {
452243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        return mCenterfreq1;
453243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
454243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
455f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne    public int getWifiMode() {
456f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne        return mWifiMode;
457f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne    }
458f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne
459947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne    public int getDtimInterval() {
460947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne        return mDtimInterval;
461947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne    }
462947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne
463243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public boolean is80211McResponderSupport() {
464b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu        return mExtendedCapabilities.is80211McRTTResponder();
465243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
466243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
46777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean isSSID_UTF8() {
4685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills        return mExtendedCapabilities.isStrictUtf8();
46977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
47077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
47177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    @Override
47277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean equals(Object thatObject) {
47377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (this == thatObject) {
47477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return true;
47577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
47677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (thatObject == null || getClass() != thatObject.getClass()) {
47777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return false;
47877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
47977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
48077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        NetworkDetail that = (NetworkDetail)thatObject;
48177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
48277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return getSSID().equals(that.getSSID()) && getBSSID() == that.getBSSID();
48377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
48477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
48577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    @Override
48677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int hashCode() {
48777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return ((mSSID.hashCode() * 31) + (int)(mBSSID >>> 32)) * 31 + (int)mBSSID;
48877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
48977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
49077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    @Override
49177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String toString() {
4921d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist        return String.format("NetworkInfo{SSID='%s', HESSID=%x, BSSID=%x, StationCount=%d, " +
4931d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist                "ChannelUtilization=%d, Capacity=%d, Ant=%s, Internet=%s, " +
494e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan                "HSRelease=%s, AnqpDomainID=%d, " +
4951d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist                "AnqpOICount=%d, RoamingConsortiums=%s}",
49677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mSSID, mHESSID, mBSSID, mStationCount,
49777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mChannelUtilization, mCapacity, mAnt, mInternet,
498e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan                mHSRelease, mAnqpDomainID,
49977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mAnqpOICount, Utils.roamingConsortiumsToString(mRoamingConsortiums));
50077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
50177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
50277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String toKeyString() {
503a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        return mHESSID != 0 ?
504866c5b061e6e762f2627e3467afc0fe6f29c2668Jan Nordqvist            String.format("'%s':%012x (%012x)", mSSID, mBSSID, mHESSID) :
505866c5b061e6e762f2627e3467afc0fe6f29c2668Jan Nordqvist            String.format("'%s':%012x", mSSID, mBSSID);
50677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
50777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
50877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String getBSSIDString() {
50977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return toMACString(mBSSID);
51077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
51177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
51259f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    /**
51359f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * Evaluates the ScanResult this NetworkDetail is built from
51459f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * returns true if built from a Beacon Frame
51559f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * returns false if built from a Probe Response
51659f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     */
51759f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    public boolean isBeaconFrame() {
51859f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        // Beacon frames have a 'Traffic Indication Map' Information element
51959f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        // Probe Responses do not. This is indicated by a DTIM period > 0
52059f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        return mDtimInterval > 0;
52159f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    }
52259f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne
52359f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    /**
52459f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * Evaluates the ScanResult this NetworkDetail is built from
52559f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * returns true if built from a hidden Beacon Frame
52659f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     * returns false if not hidden or not a Beacon
52759f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne     */
52859f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    public boolean isHiddenBeaconFrame() {
52959f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        // Hidden networks are not 80211 standard, but it is common for a hidden network beacon
53059f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        // frame to either send zero-value bytes as the SSID, or to send no bytes at all.
53159f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne        return isBeaconFrame() && mIsHiddenSsid;
53259f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne    }
53359f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne
534ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    public static String toMACString(long mac) {
53577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        StringBuilder sb = new StringBuilder();
53677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        boolean first = true;
53777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        for (int n = BYTES_IN_EUI48 - 1; n >= 0; n--) {
53877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (first) {
53977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                first = false;
54077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            } else {
54177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                sb.append(':');
54277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
54377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            sb.append(String.format("%02x", (mac >>> (n * Byte.SIZE)) & BYTE_MASK));
54477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
54577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return sb.toString();
54677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
54777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist}
548