InformationElementUtil.java revision 749ceba56556c36337dd0081b68bb6da43ae9758
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; 2625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public long[] roamingConsortiums = null; 2635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2653571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_ROAMING_CONSORTIUM) { 2663571366ac36c70746b9f013ec2b54482861c9292Randy Pan throw new IllegalArgumentException("Element id is not ROAMING_CONSORTIUM, : " 2673571366ac36c70746b9f013ec2b54482861c9292Randy Pan + ie.id); 2685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpOICount = data.get() & Constants.BYTE_MASK; 2715d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi12Length = data.get() & Constants.BYTE_MASK; 2735d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi1Length = oi12Length & Constants.NIBBLE_MASK; 2745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi2Length = (oi12Length >>> 4) & Constants.NIBBLE_MASK; 2755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi3Length = ie.bytes.length - 2 - oi1Length - oi2Length; 2765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oiCount = 0; 2775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0) { 2785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2795d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0) { 2805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0) { 2825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums = new long[oiCount]; 2875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0 && roamingConsortiums.length > 0) { 2885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[0] = 289fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi1Length); 2905d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0 && roamingConsortiums.length > 1) { 2925d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[1] = 293fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi2Length); 2945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2955d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0 && roamingConsortiums.length > 2) { 2965d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[2] = 297fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi3Length); 2985d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2995d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3005d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3015d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 3025d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class Vsa { 3035d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int ANQP_DOMID_BIT = 0x04; 3045d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 3055d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public NetworkDetail.HSRelease hsRelease = null; 3065d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int anqpDomainID = 0; // No domain ID treated the same as a 0; unique info per AP. 3075d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 3085d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 3095d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 3105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length >= 5 && data.getInt() == Constants.HS20_FRAME_PREFIX) { 3115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int hsConf = data.get() & Constants.BYTE_MASK; 3125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills switch ((hsConf >> 4) & Constants.NIBBLE_MASK) { 3135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 0: 3145d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R1; 3155d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 3165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 1: 3175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R2; 3185d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 3195d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills default: 3205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.Unknown; 3215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 3225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if ((hsConf & ANQP_DOMID_BIT) != 0) { 3245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length < 7) { 3255d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException( 3265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills "HS20 indication element too short: " + ie.bytes.length); 3275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpDomainID = data.getShort() & Constants.SHORT_MASK; 3295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3305d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 334b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 335b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * This IE contained a bit field indicating the capabilities being advertised by the STA. 336b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * The size of the bit field (number of bytes) is indicated by the |Length| field in the IE. 337b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 338b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Refer to Section 8.4.2.29 in IEEE 802.11-2012 Spec for capability associated with each 339b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * bit. 340b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 341b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Here is the wire format of this IE: 342b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * | Element ID | Length | Capabilities | 343b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 1 1 n 344b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 3455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class ExtendedCapabilities { 3465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int RTT_RESP_ENABLE_BIT = 70; 347b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu private static final int SSID_UTF8_BIT = 48; 3485d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 349b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public BitSet capabilitiesBitSet; 3505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 351b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 352b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @return true if SSID should be interpreted using UTF-8 encoding 353b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 354b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public boolean isStrictUtf8() { 355b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu return capabilitiesBitSet.get(SSID_UTF8_BIT); 3565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 358b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 359b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @return true if 802.11 MC RTT Response is enabled 360b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 361b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public boolean is80211McRTTResponder() { 362b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu return capabilitiesBitSet.get(RTT_RESP_ENABLE_BIT); 3635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 365b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public ExtendedCapabilities() { 366b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = new BitSet(); 3675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 369b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public ExtendedCapabilities(ExtendedCapabilities other) { 370b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = other.capabilitiesBitSet; 371b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu } 3725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 373b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 374b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Parse an ExtendedCapabilities from the IE containing raw bytes. 375b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 376b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @param ie The Information element data 377b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 378b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public void from(InformationElement ie) { 379b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = BitSet.valueOf(ie.bytes); 3805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3823571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3833571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 3843571366ac36c70746b9f013ec2b54482861c9292Randy Pan * parse beacon to build the capabilities 3853571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 3863571366ac36c70746b9f013ec2b54482861c9292Randy Pan * This class is used to build the capabilities string of the scan results coming 3873571366ac36c70746b9f013ec2b54482861c9292Randy Pan * from HAL. It parses the ieee beacon's capability field, WPA and RSNE IE as per spec, 3883571366ac36c70746b9f013ec2b54482861c9292Randy Pan * and builds the ScanResult.capabilities String in a way that mirrors the values returned 3893571366ac36c70746b9f013ec2b54482861c9292Randy Pan * by wpa_supplicant. 3903571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 3913571366ac36c70746b9f013ec2b54482861c9292Randy Pan public static class Capabilities { 3929b5773d2805e8c6141ca75de272921a84941546bRandy Pan private static final int CAP_ESS_BIT_OFFSET = 0; 3933571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int CAP_PRIVACY_BIT_OFFSET = 4; 3943571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3953571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_VENDOR_OUI_TYPE_ONE = 0x01f25000; 396f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang private static final int WPS_VENDOR_OUI_TYPE = 0x04f25000; 3973571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short WPA_VENDOR_OUI_VERSION = 0x0001; 3983571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short RSNE_VERSION = 0x0001; 3993571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4003571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_EAP = 0x01f25000; 4013571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_PSK = 0x02f25000; 4023571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4033571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP = 0x01ac0f00; 4043571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK = 0x02ac0f00; 4053571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_EAP = 0x03ac0f00; 4063571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_PSK = 0x04ac0f00; 4073571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP_SHA256 = 0x05ac0f00; 4083571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK_SHA256 = 0x06ac0f00; 4093571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4104d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_NONE = 0x00f25000; 4114d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_TKIP = 0x02f25000; 4124d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_CCMP = 0x04f25000; 4134d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 4144d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_NONE = 0x00ac0f00; 4154d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_TKIP = 0x02ac0f00; 4164d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_CCMP = 0x04ac0f00; 4174d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_NO_GROUP_ADDRESSED = 0x07ac0f00; 4184d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 419c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<Integer> protocol; 420c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<ArrayList<Integer>> keyManagement; 421c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<ArrayList<Integer>> pairwiseCipher; 422c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<Integer> groupCipher; 4234d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public boolean isESS; 4244d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public boolean isPrivacy; 425f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang public boolean isWPS; 4264d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 4273571366ac36c70746b9f013ec2b54482861c9292Randy Pan public Capabilities() { 4283571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4293571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4303571366ac36c70746b9f013ec2b54482861c9292Randy Pan // RSNE format (size unit: byte) 4313571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4323571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | Version | Group Data Cipher Suite | 4333571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 2 4 4343571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 4353571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 4363571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | RSN Capabilities | 4373571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 2 4383571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | PMKID Count | PMKID List | Group Management Cipher Suite | 4393571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 16 * s 4 4403571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4413571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 4423571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 4434d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private void parseRsnElement(InformationElement ie) { 4443571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 4453571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4463571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 4473571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 4483571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != RSNE_VERSION) { 4493571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 4504d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 4513571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4523571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4533571366ac36c70746b9f013ec2b54482861c9292Randy Pan // found the RSNE IE, hence start building the capability string 454c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang protocol.add(ScanResult.PROTOCOL_WPA2); 4554d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 4564d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // group data cipher suite 457c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang groupCipher.add(parseRsnCipher(buf.getInt())); 4583571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4593571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 4603571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 461c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> rsnPairwiseCipher = new ArrayList<>(); 4623571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite list 4633571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 464c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnPairwiseCipher.add(parseRsnCipher(buf.getInt())); 4653571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 466c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang pairwiseCipher.add(rsnPairwiseCipher); 4673571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4683571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 4693571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 4703571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 471c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> rsnKeyManagement = new ArrayList<>(); 4723571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4733571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 4743571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 4753571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 4763571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP: 477c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP); 4783571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4793571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK: 480c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_PSK); 4813571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4823571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_EAP: 483c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_FT_EAP); 4843571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4853571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_PSK: 486c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_FT_PSK); 4873571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4883571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP_SHA256: 489c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP_SHA256); 4903571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4913571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK_SHA256: 492c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_PSK_SHA256); 4933571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4943571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 4953571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 4963571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4973571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4983571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4994d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // Default AKM 500c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang if (rsnKeyManagement.isEmpty()) { 501c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP); 5024d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 503c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang keyManagement.add(rsnKeyManagement); 5043571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 5053571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse RSNE, buffer underflow"); 5064d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5074d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5084d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 509fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private static int parseWpaCipher(int cipher) { 5104d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang switch (cipher) { 5114d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_NONE: 512fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5134d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_TKIP: 514fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_TKIP; 5154d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_CCMP: 516fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_CCMP; 5174d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang default: 518fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang Log.w("IE_Capabilities", "Unknown WPA cipher suite: " 519fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + Integer.toHexString(cipher)); 520fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5214d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5224d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5234d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 524fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private static int parseRsnCipher(int cipher) { 5254d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang switch (cipher) { 5264d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_NONE: 527fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5284d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_TKIP: 529fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_TKIP; 5304d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_CCMP: 531fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_CCMP; 5324d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_NO_GROUP_ADDRESSED: 533fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NO_GROUP_ADDRESSED; 5344d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang default: 535fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang Log.w("IE_Capabilities", "Unknown RSN cipher suite: " 536fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + Integer.toHexString(cipher)); 537fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5383571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5393571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5403571366ac36c70746b9f013ec2b54482861c9292Randy Pan 541f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang private static boolean isWpsElement(InformationElement ie) { 542f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 543f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang try { 544f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang // WPS OUI and type 545f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang return (buf.getInt() == WPS_VENDOR_OUI_TYPE); 546f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } catch (BufferUnderflowException e) { 547f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang Log.e("IE_Capabilities", "Couldn't parse VSA IE, buffer underflow"); 548f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang return false; 549f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 550f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 551f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang 5523571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static boolean isWpaOneElement(InformationElement ie) { 5533571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 5543571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5553571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 5563571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA OUI and type 5573571366ac36c70746b9f013ec2b54482861c9292Randy Pan return (buf.getInt() == WPA_VENDOR_OUI_TYPE_ONE); 5583571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 5593571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse VSA IE, buffer underflow"); 5603571366ac36c70746b9f013ec2b54482861c9292Randy Pan return false; 5613571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5623571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5633571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5643571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA type 1 format (size unit: byte) 5653571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 5663571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | OUI | Type | Version | 5673571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 3 1 2 5684d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // | Group Data Cipher Suite | 5694d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // 4 5703571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 5713571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 5723571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | 5733571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 5743571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 5753571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 5763571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 5773571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 5784d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private void parseWpaOneElement(InformationElement ie) { 5793571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 5803571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5813571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 5823571366ac36c70746b9f013ec2b54482861c9292Randy Pan // skip WPA OUI and type parsing. isWpaOneElement() should have 5833571366ac36c70746b9f013ec2b54482861c9292Randy Pan // been called for verification before we reach here. 5843571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 5853571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5863571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 5873571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != WPA_VENDOR_OUI_VERSION) { 5883571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 5894d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 5903571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5913571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5924d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // start building the string 593c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang protocol.add(ScanResult.PROTOCOL_WPA); 5944d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 5953571366ac36c70746b9f013ec2b54482861c9292Randy Pan // group data cipher suite 596c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang groupCipher.add(parseWpaCipher(buf.getInt())); 5973571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5983571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 5993571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 600c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> wpaPairwiseCipher = new ArrayList<>(); 6013571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise chipher suite list 6023571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 603c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaPairwiseCipher.add(parseWpaCipher(buf.getInt())); 6043571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 605c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang pairwiseCipher.add(wpaPairwiseCipher); 6063571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6073571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 6083571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 6093571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 610c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> wpaKeyManagement = new ArrayList<>(); 6113571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6123571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite list 6133571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 6143571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 6153571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 6163571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_EAP: 617c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaKeyManagement.add(ScanResult.KEY_MGMT_EAP); 6183571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 6193571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_PSK: 620c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaKeyManagement.add(ScanResult.KEY_MGMT_PSK); 6213571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 6223571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 6233571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 6243571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 6253571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6263571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6274d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // Default AKM 628c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang if (wpaKeyManagement.isEmpty()) { 629c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaKeyManagement.add(ScanResult.KEY_MGMT_EAP); 6304d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 631c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang keyManagement.add(wpaKeyManagement); 6323571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 6333571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse type 1 WPA, buffer underflow"); 6343571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6353571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6363571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6373571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 6383571366ac36c70746b9f013ec2b54482861c9292Randy Pan * Parse the Information Element and the 16-bit Capability Information field 6394d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * to build the InformationElemmentUtil.capabilities object. 6403571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 6413571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param ies -- Information Element array 6423571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param beaconCap -- 16-bit Beacon Capability Information field 6433571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 6444d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 6454d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public void from(InformationElement[] ies, BitSet beaconCap) { 646c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang protocol = new ArrayList<Integer>(); 647c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang keyManagement = new ArrayList<ArrayList<Integer>>(); 648c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang groupCipher = new ArrayList<Integer>(); 649c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang pairwiseCipher = new ArrayList<ArrayList<Integer>>(); 6503571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6513571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ies == null || beaconCap == null) { 6524d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 6533571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6544d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang isESS = beaconCap.get(CAP_ESS_BIT_OFFSET); 6554d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang isPrivacy = beaconCap.get(CAP_PRIVACY_BIT_OFFSET); 6563571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (InformationElement ie : ies) { 6573571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_RSN) { 6584d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang parseRsnElement(ie); 6593571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6603571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6613571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_VSA) { 6623571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (isWpaOneElement(ie)) { 6634d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang parseWpaOneElement(ie); 6643571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 665f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang if (isWpsElement(ie)) { 666f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang // TODO(b/62134557): parse WPS IE to provide finer granularity information. 667f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang isWPS = true; 668f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 6693571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6703571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 671fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 672fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 673fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String protocolToString(int protocol) { 674fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (protocol) { 675fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_NONE: 676fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 677fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_WPA: 678fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "WPA"; 679fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_WPA2: 680fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "WPA2"; 681fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 682fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 683fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 684fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 685fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 686fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String keyManagementToString(int akm) { 687fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (akm) { 688fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_NONE: 689fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 690fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_PSK: 691fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "PSK"; 692fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_EAP: 693fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "EAP"; 694fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_FT_EAP: 695fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "FT/EAP"; 696fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_FT_PSK: 697fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "FT/PSK"; 698fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_EAP_SHA256: 699fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "EAP-SHA256"; 700fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_PSK_SHA256: 701fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "PSK-SHA256"; 702fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 703fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 704fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 705fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 706fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 707fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String cipherToString(int cipher) { 708fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (cipher) { 709fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_NONE: 710fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 711fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_CCMP: 712fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "CCMP"; 713fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_TKIP: 714fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "TKIP"; 715fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 716fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 7173571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 7184d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 7193571366ac36c70746b9f013ec2b54482861c9292Randy Pan 7204d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang /** 7214d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * Build the ScanResult.capabilities String. 7224d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * 7234d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * @return security string that mirrors what wpa_supplicant generates 7244d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang */ 7254d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public String generateCapabilitiesString() { 7264d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang String capabilities = ""; 727fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang // private Beacon without an RSNE or WPA IE, hence WEP0 728c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang boolean isWEP = (protocol.isEmpty()) && isPrivacy; 729fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 730c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang if (isWEP) { 731c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang capabilities += "[WEP]"; 732c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang } 733c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang for (int i = 0; i < protocol.size(); i++) { 7343e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius capabilities += "[" + protocolToString(protocol.get(i)); 7353e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius if (i < keyManagement.size()) { 7363e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius for (int j = 0; j < keyManagement.get(i).size(); j++) { 7373e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius capabilities += ((j == 0) ? "-" : "+") 7383e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius + keyManagementToString(keyManagement.get(i).get(j)); 7393e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius } 7404d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 7413e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius if (i < pairwiseCipher.size()) { 7423e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius for (int j = 0; j < pairwiseCipher.get(i).size(); j++) { 7433e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius capabilities += ((j == 0) ? "-" : "+") 7443e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius + cipherToString(pairwiseCipher.get(i).get(j)); 7453e80f5fa9e07c935c328fd06de555cfd5f43ed26Roshan Pius } 7464d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 7474d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang capabilities += "]"; 7484d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 7494d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang if (isESS) { 7509b5773d2805e8c6141ca75de272921a84941546bRandy Pan capabilities += "[ESS]"; 7519b5773d2805e8c6141ca75de272921a84941546bRandy Pan } 752f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang if (isWPS) { 753f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang capabilities += "[WPS]"; 754f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 755f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang 7563571366ac36c70746b9f013ec2b54482861c9292Randy Pan return capabilities; 7573571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 7583571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 759947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 760947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 761947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Parser for the Traffic Indication Map (TIM) Information Element (EID 5). This element will 762947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * only be present in scan results that are derived from a Beacon Frame, not from the more 763947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * plentiful probe responses. Call 'isValid()' after parsing, to ensure the results are correct. 764947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 765947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public static class TrafficIndicationMap { 766947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private static final int MAX_TIM_LENGTH = 254; 767947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private boolean mValid = false; 768947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mLength = 0; 769947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimCount = -1; 770947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //Negative DTIM Period means no TIM element was given this frame. 771947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimPeriod = -1; 772947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mBitmapControl = 0; 773947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 774947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 775947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Is this a valid TIM information element. 776947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 777947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public boolean isValid() { 778947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return mValid; 779947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 780947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 781947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Traffic Indication Map format (size unit: byte) 782947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 783947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //| ElementID | Length | DTIM Count | DTIM Period | BitmapControl | Partial Virtual Bitmap | 784947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 1 1 1 1 1 1 - 251 785947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 786947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 787947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // stripped off already 788947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 789947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public void from(InformationElement ie) { 790e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 791947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne if (ie == null || ie.bytes == null) return; 792947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mLength = ie.bytes.length; 793947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 794947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne try { 795947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimCount = data.get() & Constants.BYTE_MASK; 796947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimPeriod = data.get() & Constants.BYTE_MASK; 797947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mBitmapControl = data.get() & Constants.BYTE_MASK; 798947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //A valid TIM element must have atleast one more byte 799947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne data.get(); 800947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } catch (BufferUnderflowException e) { 801947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return; 802947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 80359f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne if (mLength <= MAX_TIM_LENGTH && mDtimPeriod > 0) { 804947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mValid = true; 805947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 806947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 807947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 808f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 809f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 810f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * This util class determines the 802.11 standard (a/b/g/n/ac) being used 811f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 812f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class WifiMode { 813f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_UNDEFINED = 0; // Unknown/undefined 814f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11A = 1; // 802.11a 815f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11B = 2; // 802.11b 816f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11G = 3; // 802.11g 817f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11N = 4; // 802.11n 818f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11AC = 5; // 802.11ac 819f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //<TODO> add support for 802.11ad and be more selective instead of defaulting to 11A 820f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 821f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 822f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Use frequency, max supported rate, and the existence of VHT, HT & ERP fields in scan 823f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * scan result to determine the 802.11 Wifi standard being used. 824f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 825f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int determineMode(int frequency, int maxRate, boolean foundVht, 826f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne boolean foundHt, boolean foundErp) { 827f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (foundVht) { 828f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11AC; 829f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundHt) { 830f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11N; 831f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundErp) { 832f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 833f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (frequency < 3000) { 834f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (maxRate < 24000000) { 835f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11B; 836f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 837f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 838f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 839f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 840f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11A; 841f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 842f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 843f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 844f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 845f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Map the wifiMode integer to its type, and output as String MODE_11<A/B/G/N/AC> 846f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 847f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static String toString(int mode) { 848f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(mode) { 849f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11A: 850f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11A"; 851f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11B: 852f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11B"; 853f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11G: 854f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11G"; 855f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11N: 856f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11N"; 857f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11AC: 858f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11AC"; 859f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 860f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_UNDEFINED"; 861f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 862f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 863f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 864f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 865f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 866f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Parser for both the Supported Rates & Extended Supported Rates Information Elements 867f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 868f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class SupportedRates { 869f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MASK = 0x7F; // 0111 1111 870f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean mValid = false; 871f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public ArrayList<Integer> mRates; 872f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 873f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public SupportedRates() { 874f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates = new ArrayList<Integer>(); 875f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 876f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 877f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 878f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Is this a valid Supported Rates information element. 879f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 880f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean isValid() { 881f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return mValid; 882f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 883f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 884f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 885f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * get the Rate in bits/s from associated byteval 886f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 887f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int getRateFromByte(int byteVal) { 888f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne byteVal &= MASK; 889f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(byteVal) { 890f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 2: 891f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 1000000; 892f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 4: 893f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 2000000; 894f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 11: 895f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 5500000; 896f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 12: 897f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 6000000; 898f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 18: 899f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 9000000; 900f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 22: 901f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 11000000; 902f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 24: 903f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 12000000; 904f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 36: 905f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 18000000; 906f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 44: 907f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 22000000; 908f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 48: 909f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 24000000; 910f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 66: 911f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 33000000; 912f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 72: 913f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 36000000; 914f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 96: 915f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 48000000; 916f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 108: 917f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 54000000; 918f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 919f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //ERROR UNKNOWN RATE 920f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return -1; 921f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 922f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 923f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 924f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Supported Rates format (size unit: byte) 925f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 926f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //| ElementID | Length | Supported Rates [7 Little Endian Info bits - 1 Flag bit] 927f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 1 1 1 - 8 928f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 929f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 930f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // stripped off already 931f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 932f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public void from(InformationElement ie) { 933e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 934e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart if (ie == null || ie.bytes == null || ie.bytes.length > 8 || ie.bytes.length < 1) { 935f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 936f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 937f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 938f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne try { 939f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (int i = 0; i < ie.bytes.length; i++) { 940f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne int rate = getRateFromByte(data.get()); 941f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (rate > 0) { 942f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates.add(rate); 943f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 944f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 945f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 946f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 947f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } catch (BufferUnderflowException e) { 948f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 949f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 950f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mValid = true; 951f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 952f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 953f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 954f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 955f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Lists the rates in a human readable string 956f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 957f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public String toString() { 958f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne StringBuilder sbuf = new StringBuilder(); 959f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (Integer rate : mRates) { 960f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne sbuf.append(String.format("%.1f", (double) rate / 1000000) + ", "); 961f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 962f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return sbuf.toString(); 963f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 964f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 9655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills} 966