NetworkDetail.java revision a1edc185d46d85e04930a5e12b465de9fea64afe
177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistpackage com.android.server.wifi.hotspot2;
277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport android.net.wifi.ScanResult;
473185809f4a44a8ee272afe3e5253496aeb966ceLorenzo Colittiimport android.util.Log;
577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.anqp.ANQPElement;
777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.anqp.Constants;
877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.anqp.VenueNameElement;
977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
1077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.net.ProtocolException;
11a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvistimport java.nio.BufferUnderflowException;
1277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.nio.ByteBuffer;
1377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.nio.ByteOrder;
14fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvistimport java.nio.CharBuffer;
15fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvistimport java.nio.charset.CharacterCodingException;
1677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.nio.charset.Charset;
17fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvistimport java.nio.charset.CharsetDecoder;
1877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.nio.charset.StandardCharsets;
1977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.List;
2077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.Map;
2177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
2277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport static com.android.server.wifi.anqp.Constants.BYTES_IN_EUI48;
2377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport static com.android.server.wifi.anqp.Constants.BYTE_MASK;
2477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport static com.android.server.wifi.anqp.Constants.getInteger;
2573185809f4a44a8ee272afe3e5253496aeb966ceLorenzo Colitti
2677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistpublic class NetworkDetail {
2777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
2877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final int EID_SSID = 0;
2977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final int EID_BSSLoad = 11;
30243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private static final int EID_HT_OPERATION = 61;
31243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private static final int EID_VHT_OPERATION = 192;
3277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final int EID_Interworking = 107;
3377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final int EID_RoamingConsortium = 111;
3477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final int EID_ExtendedCaps = 127;
3577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final int EID_VSA = 221;
36fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
3777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final int ANQP_DOMID_BIT = 0x04;
38243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private static final int RTT_RESP_ENABLE_BIT = 70;
3977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
4077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final long SSID_UTF8_BIT = 0x0001000000000000L;
41243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    //turn off when SHIP
42243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private static final boolean DBG = true;
43d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande    private static final boolean VDBG = false;
44d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande
45d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande    private static final String TAG = "NetworkDetail:";
4677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
4777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public enum Ant {
4877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Private,
4977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        PrivateWithGuest,
5077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        ChargeablePublic,
5177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        FreePublic,
5277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Personal,
5377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        EmergencyOnly,
5477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd6,
5577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd7,
5677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd8,
5777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd9,
5877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd10,
5977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd11,
6077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd12,
6177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Resvd13,
6277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        TestOrExperimental,
6377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Wildcard
6477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
6577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
6677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public enum HSRelease {
6777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        R1,
6877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        R2,
6977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Unknown
7077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
7177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
7277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // General identifiers:
7377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final String mSSID;
7477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final long mHESSID;
7577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final long mBSSID;
7677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
7777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    // BSS Load element:
7877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final int mStationCount;
7977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final int mChannelUtilization;
8077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final int mCapacity;
8177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
82243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    //channel detailed information
83243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe   /*
84243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    * 0 -- 20 MHz
85243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    * 1 -- 40 MHz
86243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    * 2 -- 80 MHz
87243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    * 3 -- 160 MHz
88243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    * 4 -- 80 + 80 MHz
89243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    */
90243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private final int mChannelWidth;
91243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private final int mPrimaryFreq;
92243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private final int mCenterfreq0;
93243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private final int mCenterfreq1;
94243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    private final boolean m80211McRTTResponder;
9577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    /*
9677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * From Interworking element:
9777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * mAnt non null indicates the presence of Interworking, i.e. 802.11u
9877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * mVenueGroup and mVenueType may be null if not present in the Interworking element.
9977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     */
10077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final Ant mAnt;
10177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final boolean mInternet;
10277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final VenueNameElement.VenueGroup mVenueGroup;
10377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final VenueNameElement.VenueType mVenueType;
10477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
10577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    /*
10677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * From HS20 Indication element:
10777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * mHSRelease is null only if the HS20 Indication element was not present.
10877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * mAnqpDomainID is set to -1 if not present in the element.
10977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     */
11077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final HSRelease mHSRelease;
11177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final int mAnqpDomainID;
11277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
11377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    /*
11477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * From beacon:
11577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * mAnqpOICount is how many additional OIs are available through ANQP.
11677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * mRoamingConsortiums is either null, if the element was not present, or is an array of
11777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     * 1, 2 or 3 longs in which the roaming consortium values occupy the LSBs.
11877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist     */
11977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final int mAnqpOICount;
12077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final long[] mRoamingConsortiums;
12177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
12277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final Long mExtendedCapabilities;
12377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
12477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private final Map<Constants.ANQPElementType, ANQPElement> mANQPElements;
12577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
126243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public NetworkDetail(String bssid, String infoElements, List<String> anqpLines, int freq) {
12777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
12877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (infoElements == null) {
12977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            throw new IllegalArgumentException("Null information element string");
13077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
13177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        int separator = infoElements.indexOf('=');
13277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (separator<0) {
13377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            throw new IllegalArgumentException("No element separator");
13477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
13577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
13677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mBSSID = parseMac(bssid);
13777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
13877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        ByteBuffer data = ByteBuffer.wrap(Utils.hexToBytes(infoElements.substring(separator + 1)))
13977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                .order(ByteOrder.LITTLE_ENDIAN);
14077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
14177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        String ssid = null;
14277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        byte[] ssidOctets = null;
14377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        int stationCount = 0;
14477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        int channelUtilization = 0;
14577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        int capacity = 0;
14677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
14777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Ant ant = null;
14877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        boolean internet = false;
14977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        VenueNameElement.VenueGroup venueGroup = null;
15077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        VenueNameElement.VenueType venueType = null;
15177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        long hessid = 0L;
15277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
15377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        int anqpOICount = 0;
15477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        long[] roamingConsortiums = null;
15577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
15677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        HSRelease hsRelease = null;
157ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist        int anqpDomainID = 0;       // No domain ID treated the same as a 0; unique info per AP.
15877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
15977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        Long extendedCapabilities = null;
16077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
161243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        int secondChanelOffset = 0;
162243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        int channelMode = 0;
163243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        int centerFreqIndex1 = 0;
164243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        int centerFreqIndex2 = 0;
165243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        boolean RTTResponder = false;
166243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
167fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        RuntimeException exception = null;
168207af567531a0813a9c8651d28bc4bda0ea22088xinhe
169fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        try {
170fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist            while (data.hasRemaining()) {
171fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                int eid = data.get() & Constants.BYTE_MASK;
172fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                int elementLength = data.get() & Constants.BYTE_MASK;
173fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
174fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                if (elementLength > data.remaining()) {
175fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    throw new IllegalArgumentException("Element length " + elementLength +
176fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            " exceeds payload length " + data.remaining() +
177fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            " @ " + data.position());
178fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                }
179fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
180fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                ByteBuffer element;
18177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
182fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                switch (eid) {
183fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    case EID_SSID:
184fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        ssidOctets = new byte[elementLength];
185fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        data.get(ssidOctets);
186fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
187fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    case EID_BSSLoad:
188fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        if (elementLength != 5) {
189fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            throw new IllegalArgumentException("BSS Load element length is not 5: " +
190fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    elementLength);
191fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        }
192fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        stationCount = data.getShort() & Constants.SHORT_MASK;
193fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        channelUtilization = data.get() & Constants.BYTE_MASK;
194fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        capacity = data.getShort() & Constants.SHORT_MASK;
195fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
196fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    case EID_HT_OPERATION:
197fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        element = getAndAdvancePayload(data, elementLength);
198fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        int primary_channel = element.get();
199fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        secondChanelOffset = element.get() & 0x3;
200fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
201fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    case EID_VHT_OPERATION:
202fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        element = getAndAdvancePayload(data, elementLength);
203fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        channelMode = element.get() & Constants.BYTE_MASK;
204fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        centerFreqIndex1 = element.get() & Constants.BYTE_MASK;
205fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        centerFreqIndex2 = element.get() & Constants.BYTE_MASK;
206fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
207fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    case EID_Interworking:
208fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        int anOptions = data.get() & Constants.BYTE_MASK;
209fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        ant = Ant.values()[anOptions & 0x0f];
210fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        internet = (anOptions & 0x10) != 0;
211fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        // Len 1 none, 3 venue-info, 7 HESSID, 9 venue-info & HESSID
212fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        if (elementLength == 3 || elementLength == 9) {
213fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            try {
214fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                ByteBuffer vinfo = data.duplicate();
215fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                vinfo.limit(vinfo.position() + 2);
216fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                VenueNameElement vne =
217fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                        new VenueNameElement(Constants.ANQPElementType.ANQPVenueName,
218fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                                vinfo);
219fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                venueGroup = vne.getGroup();
220fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                venueType = vne.getType();
221fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                data.getShort();
222fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            } catch (ProtocolException pe) {
223fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                /*Cannot happen*/
224fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            }
225fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        } else if (elementLength != 1 && elementLength != 7) {
226fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            throw new IllegalArgumentException("Bad Interworking element length: " +
227fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    elementLength);
22877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        }
229fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        if (elementLength == 7 || elementLength == 9) {
230fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            hessid = getInteger(data, ByteOrder.BIG_ENDIAN, 6);
23177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        }
232fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
233fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    case EID_RoamingConsortium:
234fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        anqpOICount = data.get() & Constants.BYTE_MASK;
235fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
236fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        int oi12Length = data.get() & Constants.BYTE_MASK;
237fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        int oi1Length = oi12Length & Constants.NIBBLE_MASK;
238fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        int oi2Length = (oi12Length >>> 4) & Constants.NIBBLE_MASK;
239fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        int oi3Length = elementLength - 2 - oi1Length - oi2Length;
240fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        int oiCount = 0;
241fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        if (oi1Length > 0) {
24277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                            oiCount++;
243fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            if (oi2Length > 0) {
24477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                                oiCount++;
245fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                if (oi3Length > 0) {
246fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    oiCount++;
247fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                }
24877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                            }
24977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        }
250fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        roamingConsortiums = new long[oiCount];
251fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        if (oi1Length > 0) {
252fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            roamingConsortiums[0] =
253fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    getInteger(data, ByteOrder.BIG_ENDIAN, oi1Length);
254fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        }
255fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        if (oi2Length > 0) {
256fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            roamingConsortiums[1] =
257fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    getInteger(data, ByteOrder.BIG_ENDIAN, oi2Length);
258fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        }
259fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        if (oi3Length > 0) {
260fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            roamingConsortiums[2] =
261fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    getInteger(data, ByteOrder.BIG_ENDIAN, oi3Length);
262fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        }
263fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
264fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    case EID_VSA:
265fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        element = getAndAdvancePayload(data, elementLength);
266fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        if (elementLength >= 5 && element.getInt() == Constants.HS20_FRAME_PREFIX) {
267fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            int hsConf = element.get() & Constants.BYTE_MASK;
268fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            switch ((hsConf >> 4) & Constants.NIBBLE_MASK) {
269fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                case 0:
270fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    hsRelease = HSRelease.R1;
271fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    break;
272fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                case 1:
273fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    hsRelease = HSRelease.R2;
274fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    break;
275fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                default:
276fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    hsRelease = HSRelease.Unknown;
277fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    break;
278fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            }
279fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            if ((hsConf & ANQP_DOMID_BIT) != 0) {
280fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                if (elementLength < 7) {
281fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                    throw new IllegalArgumentException(
282fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                            "HS20 indication element too short: " + elementLength);
283fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                }
284fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                anqpDomainID = element.getShort() & Constants.SHORT_MASK;
285fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            }
28677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        }
287fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
288fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    case EID_ExtendedCaps:
289398823d45a240ff90ff2ffab3ff4a8b8646f24c9Jan Nordqvist                        element = data.duplicate();
290fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        extendedCapabilities =
291fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                                Constants.getInteger(data, ByteOrder.LITTLE_ENDIAN, elementLength);
292fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
293fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        int index = RTT_RESP_ENABLE_BIT / 8;
294fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        byte offset = RTT_RESP_ENABLE_BIT % 8;
295fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
296fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        if (elementLength < index + 1) {
297fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            RTTResponder = false;
298fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            element.position(element.position() + elementLength);
299fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                            break;
30077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                        }
301fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
302fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        element.position(element.position() + index);
303fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
304fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        RTTResponder = (element.get() & (0x1 << offset)) != 0;
305fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                        break;
306fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    default:
307243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                        data.position(data.position() + elementLength);
308243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                        break;
309fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                }
310fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist            }
311fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        }
312a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        catch (IllegalArgumentException | BufferUnderflowException e) {
313a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist            Log.d("HS2J", "Caught " + e);
314fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist            if (ssidOctets == null) {
315a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist                throw e.getClass() == IllegalArgumentException.class ?
316a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist                        e : new IllegalArgumentException(e);
31777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
318a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist            exception = e;
31977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
32077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
32177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (ssidOctets != null) {
32277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            Charset encoding;
32377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (extendedCapabilities != null && (extendedCapabilities & SSID_UTF8_BIT) != 0) {
32477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                encoding = StandardCharsets.UTF_8;
32577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
32677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            else {
32777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                encoding = StandardCharsets.ISO_8859_1;
32877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
329fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
330fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist            if (exception == null) {
331fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                ssid = new String(ssidOctets, encoding);
332fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist            }
333fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist            else {
334fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                // Apply strict checking if there were previous errors:
335fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                CharsetDecoder decoder = encoding.newDecoder();
336fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                try {
337fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    CharBuffer decoded = decoder.decode(ByteBuffer.wrap(ssidOctets));
338fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    ssid = decoded.toString();
339fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                }
340fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                catch (CharacterCodingException cce) {
341fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                    throw exception;
342fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist                }
343fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist            }
34477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
34577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
34677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mSSID = ssid;
34777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mHESSID = hessid;
34877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mStationCount = stationCount;
34977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mChannelUtilization = channelUtilization;
35077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mCapacity = capacity;
35177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnt = ant;
35277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mInternet = internet;
35377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mVenueGroup = venueGroup;
35477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mVenueType = venueType;
35577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mHSRelease = hsRelease;
35677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnqpDomainID = anqpDomainID;
35777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnqpOICount = anqpOICount;
35877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mRoamingConsortiums = roamingConsortiums;
35977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mExtendedCapabilities = extendedCapabilities;
36077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mANQPElements = SupplicantBridge.parseANQPLines(anqpLines);
361243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        //set up channel info
362243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mPrimaryFreq = freq;
363243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
364243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        if (channelMode != 0) {
365243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            // 80 or 160 MHz
366243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            mChannelWidth = channelMode + 1;
367243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            mCenterfreq0 = (centerFreqIndex1 - 36) * 5 + 5180;
368243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            if(channelMode > 1) { //160MHz
369243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                mCenterfreq1 = (centerFreqIndex2 - 36) * 5 + 5180;
370243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            } else {
371243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                mCenterfreq1 = 0;
372243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            }
373243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        } else {
374243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            //20 or 40 MHz
375243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            if (secondChanelOffset != 0) {//40MHz
376243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                mChannelWidth = 1;
377243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                if (secondChanelOffset == 1) {
378243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                    mCenterfreq0 = mPrimaryFreq + 20;
379243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                } else if (secondChanelOffset == 3) {
380243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                    mCenterfreq0 = mPrimaryFreq - 20;
381243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                } else {
382243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                    mCenterfreq0 = 0;
383243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                    Log.e(TAG,"Error on secondChanelOffset");
384243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                }
385243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            } else {
386243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                mCenterfreq0 = 0;
387243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe                mChannelWidth = 0;
388243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            }
389243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe            mCenterfreq1 = 0;
390243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        }
391243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        m80211McRTTResponder = RTTResponder;
392d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        if (VDBG) {
393d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande            Log.d(TAG, mSSID + "ChannelWidth is: " + mChannelWidth + " PrimaryFreq: " + mPrimaryFreq +
394d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                    " mCenterfreq0: " + mCenterfreq0 + " mCenterfreq1: " + mCenterfreq1 +
395d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande                    (m80211McRTTResponder ? "Support RTT reponder" : "Do not support RTT responder"));
396d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande        }
39777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
39877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
399fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist    private static ByteBuffer getAndAdvancePayload(ByteBuffer data, int plLength) {
400398823d45a240ff90ff2ffab3ff4a8b8646f24c9Jan Nordqvist        ByteBuffer payload = data.duplicate().order(data.order());
401fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        payload.limit(payload.position() + plLength);
402fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        data.position(data.position() + plLength);
403fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist        return payload;
404fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist    }
405fea443b1b8807443544dfdb29a9c237b3ccf964aJan Nordqvist
40677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private NetworkDetail(NetworkDetail base, Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
40777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mSSID = base.mSSID;
40877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mBSSID = base.mBSSID;
40977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mHESSID = base.mHESSID;
41077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mStationCount = base.mStationCount;
41177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mChannelUtilization = base.mChannelUtilization;
41277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mCapacity = base.mCapacity;
41377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnt = base.mAnt;
41477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mInternet = base.mInternet;
41577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mVenueGroup = base.mVenueGroup;
41677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mVenueType = base.mVenueType;
41777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mHSRelease = base.mHSRelease;
41877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnqpDomainID = base.mAnqpDomainID;
41977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mAnqpOICount = base.mAnqpOICount;
42077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mRoamingConsortiums = base.mRoamingConsortiums;
42177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mExtendedCapabilities = base.mExtendedCapabilities;
42277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        mANQPElements = anqpElements;
423243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mChannelWidth = base.mChannelWidth;
424243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mPrimaryFreq = base.mPrimaryFreq;
425243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mCenterfreq0 = base.mCenterfreq0;
426243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        mCenterfreq1 = base.mCenterfreq1;
427243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        m80211McRTTResponder = base.m80211McRTTResponder;
42877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
42977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
43077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public NetworkDetail complete(Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
43177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return new NetworkDetail(this, anqpElements);
43277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
43377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
43477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static long parseMac(String s) {
43577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
43677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        long mac = 0;
43777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        int count = 0;
43877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        for (int n = 0; n < s.length(); n++) {
43977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            int nibble = Utils.fromHex(s.charAt(n), true);
44077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (nibble >= 0) {
44177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mac = (mac << 4) | nibble;
44277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                count++;
44377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
44477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
44577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (count < 12 || (count&1) == 1) {
44677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            throw new IllegalArgumentException("Bad MAC address: '" + s + "'");
44777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
44877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mac;
44977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
45077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
45177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean hasInterworking() {
45277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnt != null;
45377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
45477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
45577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String getSSID() {
45677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mSSID;
45777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
45877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
45977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public long getHESSID() {
46077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mHESSID;
46177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
46277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
46377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public long getBSSID() {
46477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mBSSID;
46577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
46677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
46777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getStationCount() {
46877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mStationCount;
46977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
47077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
47177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getChannelUtilization() {
47277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mChannelUtilization;
47377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
47477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
47577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getCapacity() {
47677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mCapacity;
47777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
47877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
47977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean isInterworking() {
48077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnt != null;
48177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
48277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
48377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public Ant getAnt() {
48477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnt;
48577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
48677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
48777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean isInternet() {
48877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mInternet;
48977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
49077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
49177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public VenueNameElement.VenueGroup getVenueGroup() {
49277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mVenueGroup;
49377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
49477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
49577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public VenueNameElement.VenueType getVenueType() {
49677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mVenueType;
49777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
49877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
49977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public HSRelease getHSRelease() {
50077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mHSRelease;
50177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
50277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
50377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getAnqpDomainID() {
50477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnqpDomainID;
50577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
50677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
50777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int getAnqpOICount() {
50877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mAnqpOICount;
50977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
51077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
51177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public long[] getRoamingConsortiums() {
51277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mRoamingConsortiums;
51377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
51477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
51577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public Long getExtendedCapabilities() {
51677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mExtendedCapabilities;
51777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
51877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
51977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public Map<Constants.ANQPElementType, ANQPElement> getANQPElements() {
52077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mANQPElements;
52177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
52277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
523243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public int getChannelWidth() {
524243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        return mChannelWidth;
525243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
526243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
527243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public int getCenterfreq0() {
528243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        return mCenterfreq0;
529243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
530243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
531243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public int getCenterfreq1() {
532243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        return mCenterfreq1;
533243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
534243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
535243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    public boolean is80211McResponderSupport() {
536243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        return m80211McRTTResponder;
537243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe    }
538243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe
53977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean isSSID_UTF8() {
54077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return mExtendedCapabilities != null && (mExtendedCapabilities & SSID_UTF8_BIT) != 0;
54177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
54277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
54377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    @Override
54477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public boolean equals(Object thatObject) {
54577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (this == thatObject) {
54677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return true;
54777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
54877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        if (thatObject == null || getClass() != thatObject.getClass()) {
54977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            return false;
55077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
55177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
55277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        NetworkDetail that = (NetworkDetail)thatObject;
55377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
55477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return getSSID().equals(that.getSSID()) && getBSSID() == that.getBSSID();
55577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
55677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
55777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    @Override
55877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public int hashCode() {
55977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return ((mSSID.hashCode() * 31) + (int)(mBSSID >>> 32)) * 31 + (int)mBSSID;
56077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
56177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
56277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    @Override
56377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String toString() {
56477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return String.format("NetworkInfo{mSSID='%s', mHESSID=%x, mBSSID=%x, mStationCount=%d, " +
56577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                "mChannelUtilization=%d, mCapacity=%d, mAnt=%s, mInternet=%s, " +
56677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                "mVenueGroup=%s, mVenueType=%s, mHSRelease=%s, mAnqpDomainID=%d, " +
56777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                "mAnqpOICount=%d, mRoamingConsortiums=%s}",
56877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mSSID, mHESSID, mBSSID, mStationCount,
56977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mChannelUtilization, mCapacity, mAnt, mInternet,
57077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mVenueGroup, mVenueType, mHSRelease, mAnqpDomainID,
57177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                mAnqpOICount, Utils.roamingConsortiumsToString(mRoamingConsortiums));
57277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
57377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
57477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String toKeyString() {
575a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist        return mHESSID != 0 ?
576a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist            String.format("'%s':%s (%012x)", mSSID, getBSSIDString(), mHESSID) :
577a1edc185d46d85e04930a5e12b465de9fea64afeJan Nordqvist            String.format("'%s':%s", mSSID, getBSSIDString());
57877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
57977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
58077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public String getBSSIDString() {
58177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return toMACString(mBSSID);
58277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
58377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
584ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist    public static String toMACString(long mac) {
58577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        StringBuilder sb = new StringBuilder();
58677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        boolean first = true;
58777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        for (int n = BYTES_IN_EUI48 - 1; n >= 0; n--) {
58877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            if (first) {
58977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                first = false;
59077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            } else {
59177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist                sb.append(':');
59277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            }
59377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            sb.append(String.format("%02x", (mac >>> (n * Byte.SIZE)) & BYTE_MASK));
59477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        }
59577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        return sb.toString();
59677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
59777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
59877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final String IE = "ie=" +
59977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "000477696e67" +                // SSID wing
60077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "0b052a00cf611e" +              // BSS Load 42:207:7777
60177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "6b091e0a01610408621205" +      // internet:Experimental:Vehicular:Auto:hessid
60277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "6f0a0e530111112222222229" +    // 14:111111:2222222229
60377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist            "dd07506f9a10143a01";           // r2:314
60477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
60577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    private static final String IE2 = "ie=000f4578616d706c65204e6574776f726b010882848b960c1218240301012a010432043048606c30140100000fac040100000fac040100000fac0100007f04000000806b091e07010203040506076c027f006f1001531122331020304050010203040506dd05506f9a1000";
60677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist
60777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    public static void main(String[] args) {
60877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        ScanResult scanResult = new ScanResult();
60977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        scanResult.SSID = "wing";
61077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        scanResult.BSSID = "610408";
611243931f3474f6235cfcf5c1a55fa2f192ee264aexinhe        NetworkDetail nwkDetail = new NetworkDetail(scanResult.BSSID, IE2, null, 0);
61277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist        System.out.println(nwkDetail);
61377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist    }
61477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist}
615