15d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills/* 25d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * Copyright (C) 2015 The Android Open Source Project 35d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * 45d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * Licensed under the Apache License, Version 2.0 (the "License"); 55d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * you may not use this file except in compliance with the License. 65d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * You may obtain a copy of the License at 75d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * 85d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * http://www.apache.org/licenses/LICENSE-2.0 95d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * 105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * Unless required by applicable law or agreed to in writing, software 115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * distributed under the License is distributed on an "AS IS" BASIS, 125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * See the License for the specific language governing permissions and 145d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * limitations under the License. 155d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills */ 165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willspackage com.android.server.wifi.util; 175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 18fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wangimport android.net.wifi.ScanResult; 195d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport android.net.wifi.ScanResult.InformationElement; 205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport android.util.Log; 2159f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne 22fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiuimport com.android.server.wifi.ByteBufferReader; 235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport com.android.server.wifi.hotspot2.NetworkDetail; 24fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiuimport com.android.server.wifi.hotspot2.anqp.Constants; 2559f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne 263571366ac36c70746b9f013ec2b54482861c9292Randy Panimport java.nio.BufferUnderflowException; 275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport java.nio.ByteBuffer; 285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport java.nio.ByteOrder; 295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport java.util.ArrayList; 303571366ac36c70746b9f013ec2b54482861c9292Randy Panimport java.util.BitSet; 315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willspublic class InformationElementUtil { 339e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu private static final String TAG = "InformationElementUtil"; 345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static InformationElement[] parseInformationElements(byte[] bytes) { 36da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein if (bytes == null) { 37da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein return new InformationElement[0]; 38da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein } 395d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); 405d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ArrayList<InformationElement> infoElements = new ArrayList<>(); 425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills boolean found_ssid = false; 435d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills while (data.remaining() > 1) { 445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int eid = data.get() & Constants.BYTE_MASK; 455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int elementLength = data.get() & Constants.BYTE_MASK; 465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 473571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (elementLength > data.remaining() || (eid == InformationElement.EID_SSID 483571366ac36c70746b9f013ec2b54482861c9292Randy Pan && found_ssid)) { 49da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // APs often pad the data with bytes that happen to match that of the EID_SSID 50da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // marker. This is not due to a known issue for APs to incorrectly send the SSID 51da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // name multiple times. 525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 543571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (eid == InformationElement.EID_SSID) { 555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills found_ssid = true; 565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills InformationElement ie = new InformationElement(); 595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ie.id = eid; 605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ie.bytes = new byte[elementLength]; 615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills data.get(ie.bytes); 625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills infoElements.add(ie); 635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return infoElements.toArray(new InformationElement[infoElements.size()]); 655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 679e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu /** 689e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * Parse and retrieve the Roaming Consortium Information Element from the list of IEs. 699e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * 709e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * @param ies List of IEs to retrieve from 719e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * @return {@link RoamingConsortium} 729e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu */ 739e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu public static RoamingConsortium getRoamingConsortiumIE(InformationElement[] ies) { 749e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu RoamingConsortium roamingConsortium = new RoamingConsortium(); 759e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu if (ies != null) { 769e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu for (InformationElement ie : ies) { 779e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu if (ie.id == InformationElement.EID_ROAMING_CONSORTIUM) { 789e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu try { 799e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu roamingConsortium.from(ie); 809e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } catch (RuntimeException e) { 819e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu Log.e(TAG, "Failed to parse Roaming Consortium IE: " + e.getMessage()); 829e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 839e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 849e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 859e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 869e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu return roamingConsortium; 879e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 889e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu 899e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu /** 909e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * Parse and retrieve the Hotspot 2.0 Vendor Specific Information Element from the list of IEs. 919e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * 929e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * @param ies List of IEs to retrieve from 939e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * @return {@link Vsa} 949e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu */ 959e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu public static Vsa getHS2VendorSpecificIE(InformationElement[] ies) { 969e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu Vsa vsa = new Vsa(); 979e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu if (ies != null) { 989e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu for (InformationElement ie : ies) { 999e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu if (ie.id == InformationElement.EID_VSA) { 1009e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu try { 1019e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu vsa.from(ie); 1029e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } catch (RuntimeException e) { 1039e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu Log.e(TAG, "Failed to parse Vendor Specific IE: " + e.getMessage()); 1049e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 1059e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 1069e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 1079e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 1089e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu return vsa; 1099e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 1109e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu 1119e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu /** 1129e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * Parse and retrieve the Interworking information element from the list of IEs. 1139e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * 1149e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * @param ies List of IEs to retrieve from 1159e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu * @return {@link Interworking} 1169e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu */ 1179e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu public static Interworking getInterworkingIE(InformationElement[] ies) { 1189e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu Interworking interworking = new Interworking(); 1199e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu if (ies != null) { 1209e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu for (InformationElement ie : ies) { 1219e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu if (ie.id == InformationElement.EID_INTERWORKING) { 1229e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu try { 1239e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu interworking.from(ie); 1249e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } catch (RuntimeException e) { 1259e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu Log.e(TAG, "Failed to parse Interworking IE: " + e.getMessage()); 1269e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 1279e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 1289e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 1299e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 1309e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu return interworking; 1319e83e33d444446e59aa59fc355972ff804d8eafaPeter Qiu } 1325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class BssLoad { 1345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int stationCount = 0; 1355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int channelUtilization = 0; 1365d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int capacity = 0; 1375d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1393571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_BSS_LOAD) { 1405d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not BSS_LOAD, : " + ie.id); 1415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length != 5) { 1433571366ac36c70746b9f013ec2b54482861c9292Randy Pan throw new IllegalArgumentException("BSS Load element length is not 5: " 1443571366ac36c70746b9f013ec2b54482861c9292Randy Pan + ie.bytes.length); 1455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 1475d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills stationCount = data.getShort() & Constants.SHORT_MASK; 1485d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills channelUtilization = data.get() & Constants.BYTE_MASK; 1495d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills capacity = data.getShort() & Constants.SHORT_MASK; 1505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1515d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class HtOperation { 1545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int secondChannelOffset = 0; 1555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getChannelWidth() { 1573571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (secondChannelOffset != 0) { 1585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 1; 1593571366ac36c70746b9f013ec2b54482861c9292Randy Pan } else { 1605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq0(int primaryFrequency) { 1659f743918a412fec9ad5a0386fbf6cf0361313f58xinhe //40 MHz 1669f743918a412fec9ad5a0386fbf6cf0361313f58xinhe if (secondChannelOffset != 0) { 1675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (secondChannelOffset == 1) { 1689f743918a412fec9ad5a0386fbf6cf0361313f58xinhe return primaryFrequency + 10; 1695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else if (secondChannelOffset == 3) { 1709f743918a412fec9ad5a0386fbf6cf0361313f58xinhe return primaryFrequency - 10; 1715d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 1725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills Log.e("HtOperation", "Error on secondChannelOffset: " + secondChannelOffset); 1735d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 1765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1795d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1813571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_HT_OPERATION) { 1825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not HT_OPERATION, : " + ie.id); 1835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills secondChannelOffset = ie.bytes[1] & 0x3; 1855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class VhtOperation { 1895d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int channelMode = 0; 1905d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int centerFreqIndex1 = 0; 1915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int centerFreqIndex2 = 0; 1925d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1935d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean isValid() { 1945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return channelMode != 0; 1955d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1965d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1975d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getChannelWidth() { 1985d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return channelMode + 1; 1995d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2005d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2015d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq0() { 2025d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills //convert channel index to frequency in MHz, channel 36 is 5180MHz 2035d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return (centerFreqIndex1 - 36) * 5 + 5180; 2045d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2055d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2065d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq1() { 2073571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (channelMode > 1) { //160MHz 2085d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return (centerFreqIndex2 - 36) * 5 + 5180; 2095d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 2105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 2115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2145d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2153571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_VHT_OPERATION) { 2165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not VHT_OPERATION, : " + ie.id); 2175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2185d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills channelMode = ie.bytes[0] & Constants.BYTE_MASK; 2195d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills centerFreqIndex1 = ie.bytes[1] & Constants.BYTE_MASK; 2205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills centerFreqIndex2 = ie.bytes[2] & Constants.BYTE_MASK; 2215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class Interworking { 2255d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public NetworkDetail.Ant ant = null; 2265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean internet = false; 2275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public long hessid = 0L; 2285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2303571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_INTERWORKING) { 2315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not INTERWORKING, : " + ie.id); 2325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int anOptions = data.get() & Constants.BYTE_MASK; 2355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ant = NetworkDetail.Ant.values()[anOptions & 0x0f]; 2365d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills internet = (anOptions & 0x10) != 0; 237e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // There are only three possible lengths for the Interworking IE: 238e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 1: Access Network Options only 239e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 3: Access Network Options & Venue Info 240e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 7: Access Network Options & HESSID 241e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 9: Access Network Options, Venue Info, & HESSID 242e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan if (ie.bytes.length != 1 243e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan && ie.bytes.length != 3 244e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan && ie.bytes.length != 7 245e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan && ie.bytes.length != 9) { 246e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan throw new IllegalArgumentException( 247e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan "Bad Interworking element length: " + ie.bytes.length); 2485d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 249e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan 250749ceba56556c36337dd0081b68bb6da43ae9758Etan Cohen if (ie.bytes.length == 3 || ie.bytes.length == 9) { 251749ceba56556c36337dd0081b68bb6da43ae9758Etan Cohen int venueInfo = (int) ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, 2); 252749ceba56556c36337dd0081b68bb6da43ae9758Etan Cohen } 253749ceba56556c36337dd0081b68bb6da43ae9758Etan Cohen 2545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length == 7 || ie.bytes.length == 9) { 255fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu hessid = ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, 6); 2565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class RoamingConsortium { 2615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int anqpOICount = 0; 2622e889dc0b3f348f45cc5f5006d8784bed30583a9Masashi Honma 2632e889dc0b3f348f45cc5f5006d8784bed30583a9Masashi Honma private long[] roamingConsortiums = null; 2642e889dc0b3f348f45cc5f5006d8784bed30583a9Masashi Honma 2652e889dc0b3f348f45cc5f5006d8784bed30583a9Masashi Honma public long[] getRoamingConsortiums() { 2662e889dc0b3f348f45cc5f5006d8784bed30583a9Masashi Honma return roamingConsortiums; 2672e889dc0b3f348f45cc5f5006d8784bed30583a9Masashi Honma } 2685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2703571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_ROAMING_CONSORTIUM) { 2713571366ac36c70746b9f013ec2b54482861c9292Randy Pan throw new IllegalArgumentException("Element id is not ROAMING_CONSORTIUM, : " 2723571366ac36c70746b9f013ec2b54482861c9292Randy Pan + ie.id); 2735d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpOICount = data.get() & Constants.BYTE_MASK; 2765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi12Length = data.get() & Constants.BYTE_MASK; 2785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi1Length = oi12Length & Constants.NIBBLE_MASK; 2795d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi2Length = (oi12Length >>> 4) & Constants.NIBBLE_MASK; 2805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi3Length = ie.bytes.length - 2 - oi1Length - oi2Length; 2815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oiCount = 0; 2825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0) { 2835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0) { 2855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0) { 2875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2895d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2905d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums = new long[oiCount]; 2925d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0 && roamingConsortiums.length > 0) { 2935d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[0] = 294fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi1Length); 2955d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2965d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0 && roamingConsortiums.length > 1) { 2975d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[1] = 298fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi2Length); 2995d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3005d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0 && roamingConsortiums.length > 2) { 3015d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[2] = 302fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi3Length); 3035d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3045d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3055d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3065d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 3075d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class Vsa { 3085d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int ANQP_DOMID_BIT = 0x04; 3095d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 3105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public NetworkDetail.HSRelease hsRelease = null; 3115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int anqpDomainID = 0; // No domain ID treated the same as a 0; unique info per AP. 3125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 3135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 3145d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 3155d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length >= 5 && data.getInt() == Constants.HS20_FRAME_PREFIX) { 3165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int hsConf = data.get() & Constants.BYTE_MASK; 3175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills switch ((hsConf >> 4) & Constants.NIBBLE_MASK) { 3185d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 0: 3195d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R1; 3205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 3215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 1: 3225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R2; 3235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 3245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills default: 3255d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.Unknown; 3265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 3275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if ((hsConf & ANQP_DOMID_BIT) != 0) { 3295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length < 7) { 3305d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException( 3315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills "HS20 indication element too short: " + ie.bytes.length); 3325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpDomainID = data.getShort() & Constants.SHORT_MASK; 3345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3365d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3375d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 339b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 340b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * This IE contained a bit field indicating the capabilities being advertised by the STA. 341b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * The size of the bit field (number of bytes) is indicated by the |Length| field in the IE. 342b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 343b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Refer to Section 8.4.2.29 in IEEE 802.11-2012 Spec for capability associated with each 344b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * bit. 345b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 346b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Here is the wire format of this IE: 347b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * | Element ID | Length | Capabilities | 348b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 1 1 n 349b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 3505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class ExtendedCapabilities { 3515d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int RTT_RESP_ENABLE_BIT = 70; 352b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu private static final int SSID_UTF8_BIT = 48; 3535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 354b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public BitSet capabilitiesBitSet; 3555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 356b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 357b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @return true if SSID should be interpreted using UTF-8 encoding 358b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 359b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public boolean isStrictUtf8() { 360b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu return capabilitiesBitSet.get(SSID_UTF8_BIT); 3615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 363b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 364b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @return true if 802.11 MC RTT Response is enabled 365b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 366b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public boolean is80211McRTTResponder() { 367b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu return capabilitiesBitSet.get(RTT_RESP_ENABLE_BIT); 3685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 370b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public ExtendedCapabilities() { 371b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = new BitSet(); 3725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3735d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 374b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public ExtendedCapabilities(ExtendedCapabilities other) { 375b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = other.capabilitiesBitSet; 376b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu } 3775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 378b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 379b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Parse an ExtendedCapabilities from the IE containing raw bytes. 380b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 381b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @param ie The Information element data 382b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 383b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public void from(InformationElement ie) { 384b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = BitSet.valueOf(ie.bytes); 3855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3873571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3883571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 3893571366ac36c70746b9f013ec2b54482861c9292Randy Pan * parse beacon to build the capabilities 3903571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 3913571366ac36c70746b9f013ec2b54482861c9292Randy Pan * This class is used to build the capabilities string of the scan results coming 3923571366ac36c70746b9f013ec2b54482861c9292Randy Pan * from HAL. It parses the ieee beacon's capability field, WPA and RSNE IE as per spec, 3933571366ac36c70746b9f013ec2b54482861c9292Randy Pan * and builds the ScanResult.capabilities String in a way that mirrors the values returned 3943571366ac36c70746b9f013ec2b54482861c9292Randy Pan * by wpa_supplicant. 3953571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 3963571366ac36c70746b9f013ec2b54482861c9292Randy Pan public static class Capabilities { 3979b5773d2805e8c6141ca75de272921a84941546bRandy Pan private static final int CAP_ESS_BIT_OFFSET = 0; 3983571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int CAP_PRIVACY_BIT_OFFSET = 4; 3993571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4003571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_VENDOR_OUI_TYPE_ONE = 0x01f25000; 401f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang private static final int WPS_VENDOR_OUI_TYPE = 0x04f25000; 4023571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short WPA_VENDOR_OUI_VERSION = 0x0001; 4033571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short RSNE_VERSION = 0x0001; 4043571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4053571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_EAP = 0x01f25000; 4063571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_PSK = 0x02f25000; 4073571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4083571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP = 0x01ac0f00; 4093571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK = 0x02ac0f00; 4103571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_EAP = 0x03ac0f00; 4113571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_PSK = 0x04ac0f00; 4123571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP_SHA256 = 0x05ac0f00; 4133571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK_SHA256 = 0x06ac0f00; 4143571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4154d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_NONE = 0x00f25000; 4164d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_TKIP = 0x02f25000; 4174d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_CCMP = 0x04f25000; 4184d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 4194d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_NONE = 0x00ac0f00; 4204d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_TKIP = 0x02ac0f00; 4214d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_CCMP = 0x04ac0f00; 4224d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_NO_GROUP_ADDRESSED = 0x07ac0f00; 4234d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 424c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<Integer> protocol; 425c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<ArrayList<Integer>> keyManagement; 426c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<ArrayList<Integer>> pairwiseCipher; 427c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<Integer> groupCipher; 4284d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public boolean isESS; 4294d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public boolean isPrivacy; 430f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang public boolean isWPS; 4314d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 4323571366ac36c70746b9f013ec2b54482861c9292Randy Pan public Capabilities() { 4333571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4343571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4353571366ac36c70746b9f013ec2b54482861c9292Randy Pan // RSNE format (size unit: byte) 4363571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4373571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | Version | Group Data Cipher Suite | 4383571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 2 4 4393571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 4403571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 4413571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | RSN Capabilities | 4423571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 2 4433571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | PMKID Count | PMKID List | Group Management Cipher Suite | 4443571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 16 * s 4 4453571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4463571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 4473571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 4484d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private void parseRsnElement(InformationElement ie) { 4493571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 4503571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4513571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 4523571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 4533571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != RSNE_VERSION) { 4543571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 4554d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 4563571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4573571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4583571366ac36c70746b9f013ec2b54482861c9292Randy Pan // found the RSNE IE, hence start building the capability string 459c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang protocol.add(ScanResult.PROTOCOL_WPA2); 4604d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 4614d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // group data cipher suite 462c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang groupCipher.add(parseRsnCipher(buf.getInt())); 4633571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4643571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 4653571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 466c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> rsnPairwiseCipher = new ArrayList<>(); 4673571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite list 4683571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 469c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnPairwiseCipher.add(parseRsnCipher(buf.getInt())); 4703571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 471c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang pairwiseCipher.add(rsnPairwiseCipher); 4723571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4733571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 4743571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 4753571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 476c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> rsnKeyManagement = new ArrayList<>(); 4773571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4783571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 4793571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 4803571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 4813571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP: 482c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP); 4833571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4843571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK: 485c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_PSK); 4863571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4873571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_EAP: 488c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_FT_EAP); 4893571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4903571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_PSK: 491c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_FT_PSK); 4923571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4933571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP_SHA256: 494c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP_SHA256); 4953571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4963571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK_SHA256: 497c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_PSK_SHA256); 4983571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4993571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 5003571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 5013571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 5023571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5033571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5044d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // Default AKM 505c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang if (rsnKeyManagement.isEmpty()) { 506c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP); 5074d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 508c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang keyManagement.add(rsnKeyManagement); 5093571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 5103571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse RSNE, buffer underflow"); 5114d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5124d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5134d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 514fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private static int parseWpaCipher(int cipher) { 5154d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang switch (cipher) { 5164d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_NONE: 517fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5184d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_TKIP: 519fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_TKIP; 5204d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_CCMP: 521fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_CCMP; 5224d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang default: 523fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang Log.w("IE_Capabilities", "Unknown WPA cipher suite: " 524fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + Integer.toHexString(cipher)); 525fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5264d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5274d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5284d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 529fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private static int parseRsnCipher(int cipher) { 5304d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang switch (cipher) { 5314d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_NONE: 532fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5334d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_TKIP: 534fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_TKIP; 5354d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_CCMP: 536fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_CCMP; 5374d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_NO_GROUP_ADDRESSED: 538fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NO_GROUP_ADDRESSED; 5394d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang default: 540fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang Log.w("IE_Capabilities", "Unknown RSN cipher suite: " 541fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + Integer.toHexString(cipher)); 542fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5433571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5443571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5453571366ac36c70746b9f013ec2b54482861c9292Randy Pan 546f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang private static boolean isWpsElement(InformationElement ie) { 547f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 548f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang try { 549f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang // WPS OUI and type 550f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang return (buf.getInt() == WPS_VENDOR_OUI_TYPE); 551f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } catch (BufferUnderflowException e) { 552f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang Log.e("IE_Capabilities", "Couldn't parse VSA IE, buffer underflow"); 553f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang return false; 554f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 555f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 556f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang 5573571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static boolean isWpaOneElement(InformationElement ie) { 5583571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 5593571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5603571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 5613571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA OUI and type 5623571366ac36c70746b9f013ec2b54482861c9292Randy Pan return (buf.getInt() == WPA_VENDOR_OUI_TYPE_ONE); 5633571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 5643571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse VSA IE, buffer underflow"); 5653571366ac36c70746b9f013ec2b54482861c9292Randy Pan return false; 5663571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5673571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5683571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5693571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA type 1 format (size unit: byte) 5703571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 5713571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | OUI | Type | Version | 5723571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 3 1 2 5734d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // | Group Data Cipher Suite | 5744d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // 4 5753571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 5763571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 5773571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | 5783571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 5793571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 5803571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 5813571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 5823571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 5834d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private void parseWpaOneElement(InformationElement ie) { 5843571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 5853571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5863571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 5873571366ac36c70746b9f013ec2b54482861c9292Randy Pan // skip WPA OUI and type parsing. isWpaOneElement() should have 5883571366ac36c70746b9f013ec2b54482861c9292Randy Pan // been called for verification before we reach here. 5893571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 5903571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5913571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 5923571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != WPA_VENDOR_OUI_VERSION) { 5933571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 5944d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 5953571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5963571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5974d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // start building the string 598c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang protocol.add(ScanResult.PROTOCOL_WPA); 5994d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 6003571366ac36c70746b9f013ec2b54482861c9292Randy Pan // group data cipher suite 601c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang groupCipher.add(parseWpaCipher(buf.getInt())); 6023571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6033571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 6043571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 605c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> wpaPairwiseCipher = new ArrayList<>(); 6063571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise chipher suite list 6073571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 608c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaPairwiseCipher.add(parseWpaCipher(buf.getInt())); 6093571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 610c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang pairwiseCipher.add(wpaPairwiseCipher); 6113571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6123571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 6133571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 6143571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 615c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> wpaKeyManagement = new ArrayList<>(); 6163571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6173571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite list 6183571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 6193571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 6203571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 6213571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_EAP: 622c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaKeyManagement.add(ScanResult.KEY_MGMT_EAP); 6233571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 6243571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_PSK: 625c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaKeyManagement.add(ScanResult.KEY_MGMT_PSK); 6263571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 6273571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 6283571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 6293571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 6303571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6313571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6324d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // Default AKM 633c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang if (wpaKeyManagement.isEmpty()) { 634c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaKeyManagement.add(ScanResult.KEY_MGMT_EAP); 6354d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 636c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang keyManagement.add(wpaKeyManagement); 6373571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 6383571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse type 1 WPA, buffer underflow"); 6393571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6403571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6413571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6423571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 6433571366ac36c70746b9f013ec2b54482861c9292Randy Pan * Parse the Information Element and the 16-bit Capability Information field 6444d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * to build the InformationElemmentUtil.capabilities object. 6453571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 6463571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param ies -- Information Element array 6473571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param beaconCap -- 16-bit Beacon Capability Information field 6483571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 6494d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 6504d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public void from(InformationElement[] ies, BitSet beaconCap) { 651c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang protocol = new ArrayList<Integer>(); 652c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang keyManagement = new ArrayList<ArrayList<Integer>>(); 653c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang groupCipher = new ArrayList<Integer>(); 654c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang pairwiseCipher = new ArrayList<ArrayList<Integer>>(); 6553571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6563571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ies == null || beaconCap == null) { 6574d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 6583571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6594d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang isESS = beaconCap.get(CAP_ESS_BIT_OFFSET); 6604d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang isPrivacy = beaconCap.get(CAP_PRIVACY_BIT_OFFSET); 6613571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (InformationElement ie : ies) { 6623571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_RSN) { 6634d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang parseRsnElement(ie); 6643571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6653571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6663571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_VSA) { 6673571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (isWpaOneElement(ie)) { 6684d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang parseWpaOneElement(ie); 6693571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 670f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang if (isWpsElement(ie)) { 671f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang // TODO(b/62134557): parse WPS IE to provide finer granularity information. 672f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang isWPS = true; 673f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 6743571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6753571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 676fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 677fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 678fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String protocolToString(int protocol) { 679fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (protocol) { 680fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_NONE: 681fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 682fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_WPA: 683fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "WPA"; 684fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_WPA2: 685fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "WPA2"; 686fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 687fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 688fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 689fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 690fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 691fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String keyManagementToString(int akm) { 692fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (akm) { 693fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_NONE: 694fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 695fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_PSK: 696fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "PSK"; 697fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_EAP: 698fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "EAP"; 699fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_FT_EAP: 700fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "FT/EAP"; 701fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_FT_PSK: 702fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "FT/PSK"; 703fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_EAP_SHA256: 704fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "EAP-SHA256"; 705fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_PSK_SHA256: 706fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "PSK-SHA256"; 707fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 708fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 709fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 710fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 711fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 712fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String cipherToString(int cipher) { 713fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (cipher) { 714fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_NONE: 715fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 716fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_CCMP: 717fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "CCMP"; 718fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_TKIP: 719fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "TKIP"; 720fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 721fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 7223571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 7234d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 7243571366ac36c70746b9f013ec2b54482861c9292Randy Pan 7254d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang /** 7264d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * Build the ScanResult.capabilities String. 7274d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * 7284d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * @return security string that mirrors what wpa_supplicant generates 7294d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang */ 7304d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public String generateCapabilitiesString() { 7314d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang String capabilities = ""; 732fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang // private Beacon without an RSNE or WPA IE, hence WEP0 733c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang boolean isWEP = (protocol.isEmpty()) && isPrivacy; 734fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 735c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang if (isWEP) { 736c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang capabilities += "[WEP]"; 737c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang } 738c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang for (int i = 0; i < protocol.size(); i++) { 7393e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius capabilities += "[" + protocolToString(protocol.get(i)); 7403e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius if (i < keyManagement.size()) { 7413e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius for (int j = 0; j < keyManagement.get(i).size(); j++) { 7423e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius capabilities += ((j == 0) ? "-" : "+") 7433e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius + keyManagementToString(keyManagement.get(i).get(j)); 7443e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius } 7454d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 7463e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius if (i < pairwiseCipher.size()) { 7473e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius for (int j = 0; j < pairwiseCipher.get(i).size(); j++) { 7483e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius capabilities += ((j == 0) ? "-" : "+") 7493e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius + cipherToString(pairwiseCipher.get(i).get(j)); 7503e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius } 7514d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 7524d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang capabilities += "]"; 7534d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 7544d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang if (isESS) { 7559b5773d2805e8c6141ca75de272921a84941546bRandy Pan capabilities += "[ESS]"; 7569b5773d2805e8c6141ca75de272921a84941546bRandy Pan } 757f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang if (isWPS) { 758f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang capabilities += "[WPS]"; 759f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 760f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang 7613571366ac36c70746b9f013ec2b54482861c9292Randy Pan return capabilities; 7623571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 7633571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 764947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 765947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 766947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Parser for the Traffic Indication Map (TIM) Information Element (EID 5). This element will 767947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * only be present in scan results that are derived from a Beacon Frame, not from the more 768947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * plentiful probe responses. Call 'isValid()' after parsing, to ensure the results are correct. 769947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 770947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public static class TrafficIndicationMap { 771947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private static final int MAX_TIM_LENGTH = 254; 772947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private boolean mValid = false; 773947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mLength = 0; 774947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimCount = -1; 775947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //Negative DTIM Period means no TIM element was given this frame. 776947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimPeriod = -1; 777947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mBitmapControl = 0; 778947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 779947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 780947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Is this a valid TIM information element. 781947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 782947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public boolean isValid() { 783947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return mValid; 784947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 785947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 786947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Traffic Indication Map format (size unit: byte) 787947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 788947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //| ElementID | Length | DTIM Count | DTIM Period | BitmapControl | Partial Virtual Bitmap | 789947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 1 1 1 1 1 1 - 251 790947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 791947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 792947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // stripped off already 793947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 794947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public void from(InformationElement ie) { 795e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 796947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne if (ie == null || ie.bytes == null) return; 797947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mLength = ie.bytes.length; 798947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 799947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne try { 800947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimCount = data.get() & Constants.BYTE_MASK; 801947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimPeriod = data.get() & Constants.BYTE_MASK; 802947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mBitmapControl = data.get() & Constants.BYTE_MASK; 803947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //A valid TIM element must have atleast one more byte 804947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne data.get(); 805947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } catch (BufferUnderflowException e) { 806947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return; 807947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 80859f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne if (mLength <= MAX_TIM_LENGTH && mDtimPeriod > 0) { 809947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mValid = true; 810947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 811947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 812947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 813f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 814f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 815f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * This util class determines the 802.11 standard (a/b/g/n/ac) being used 816f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 817f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class WifiMode { 818f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_UNDEFINED = 0; // Unknown/undefined 819f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11A = 1; // 802.11a 820f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11B = 2; // 802.11b 821f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11G = 3; // 802.11g 822f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11N = 4; // 802.11n 823f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11AC = 5; // 802.11ac 824f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //<TODO> add support for 802.11ad and be more selective instead of defaulting to 11A 825f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 826f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 827f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Use frequency, max supported rate, and the existence of VHT, HT & ERP fields in scan 828f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * scan result to determine the 802.11 Wifi standard being used. 829f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 830f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int determineMode(int frequency, int maxRate, boolean foundVht, 831f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne boolean foundHt, boolean foundErp) { 832f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (foundVht) { 833f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11AC; 834f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundHt) { 835f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11N; 836f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundErp) { 837f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 838f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (frequency < 3000) { 839f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (maxRate < 24000000) { 840f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11B; 841f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 842f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 843f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 844f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 845f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11A; 846f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 847f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 848f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 849f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 850f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Map the wifiMode integer to its type, and output as String MODE_11<A/B/G/N/AC> 851f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 852f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static String toString(int mode) { 853f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(mode) { 854f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11A: 855f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11A"; 856f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11B: 857f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11B"; 858f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11G: 859f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11G"; 860f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11N: 861f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11N"; 862f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11AC: 863f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11AC"; 864f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 865f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_UNDEFINED"; 866f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 867f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 868f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 869f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 870f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 871f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Parser for both the Supported Rates & Extended Supported Rates Information Elements 872f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 873f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class SupportedRates { 874f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MASK = 0x7F; // 0111 1111 875f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean mValid = false; 876f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public ArrayList<Integer> mRates; 877f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 878f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public SupportedRates() { 879f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates = new ArrayList<Integer>(); 880f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 881f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 882f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 883f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Is this a valid Supported Rates information element. 884f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 885f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean isValid() { 886f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return mValid; 887f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 888f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 889f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 890f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * get the Rate in bits/s from associated byteval 891f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 892f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int getRateFromByte(int byteVal) { 893f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne byteVal &= MASK; 894f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(byteVal) { 895f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 2: 896f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 1000000; 897f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 4: 898f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 2000000; 899f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 11: 900f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 5500000; 901f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 12: 902f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 6000000; 903f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 18: 904f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 9000000; 905f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 22: 906f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 11000000; 907f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 24: 908f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 12000000; 909f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 36: 910f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 18000000; 911f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 44: 912f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 22000000; 913f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 48: 914f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 24000000; 915f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 66: 916f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 33000000; 917f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 72: 918f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 36000000; 919f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 96: 920f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 48000000; 921f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 108: 922f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 54000000; 923f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 924f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //ERROR UNKNOWN RATE 925f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return -1; 926f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 927f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 928f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 929f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Supported Rates format (size unit: byte) 930f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 931f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //| ElementID | Length | Supported Rates [7 Little Endian Info bits - 1 Flag bit] 932f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 1 1 1 - 8 933f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 934f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 935f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // stripped off already 936f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 937f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public void from(InformationElement ie) { 938e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 939e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart if (ie == null || ie.bytes == null || ie.bytes.length > 8 || ie.bytes.length < 1) { 940f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 941f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 942f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 943f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne try { 944f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (int i = 0; i < ie.bytes.length; i++) { 945f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne int rate = getRateFromByte(data.get()); 946f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (rate > 0) { 947f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates.add(rate); 948f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 949f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 950f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 951f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 952f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } catch (BufferUnderflowException e) { 953f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 954f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 955f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mValid = true; 956f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 957f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 958f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 959f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 960f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Lists the rates in a human readable string 961f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 962f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public String toString() { 963f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne StringBuilder sbuf = new StringBuilder(); 964f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (Integer rate : mRates) { 965f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne sbuf.append(String.format("%.1f", (double) rate / 1000000) + ", "); 966f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 967f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return sbuf.toString(); 968f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 969f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 9705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills} 971