InformationElementUtil.java revision f7364b4baea06722022b7c6519ace0556481cc06
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 2505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length == 7 || ie.bytes.length == 9) { 251fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu hessid = ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, 6); 2525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class RoamingConsortium { 2575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int anqpOICount = 0; 2585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public long[] roamingConsortiums = null; 2595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2613571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_ROAMING_CONSORTIUM) { 2623571366ac36c70746b9f013ec2b54482861c9292Randy Pan throw new IllegalArgumentException("Element id is not ROAMING_CONSORTIUM, : " 2633571366ac36c70746b9f013ec2b54482861c9292Randy Pan + ie.id); 2645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpOICount = data.get() & Constants.BYTE_MASK; 2675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi12Length = data.get() & Constants.BYTE_MASK; 2695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi1Length = oi12Length & Constants.NIBBLE_MASK; 2705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi2Length = (oi12Length >>> 4) & Constants.NIBBLE_MASK; 2715d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi3Length = ie.bytes.length - 2 - oi1Length - oi2Length; 2725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oiCount = 0; 2735d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0) { 2745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0) { 2765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0) { 2785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2795d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums = new long[oiCount]; 2835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0 && roamingConsortiums.length > 0) { 2845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[0] = 285fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi1Length); 2865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0 && roamingConsortiums.length > 1) { 2885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[1] = 289fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi2Length); 2905d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0 && roamingConsortiums.length > 2) { 2925d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[2] = 293fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi3Length); 2945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2955d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2965d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2975d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2985d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class Vsa { 2995d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int ANQP_DOMID_BIT = 0x04; 3005d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 3015d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public NetworkDetail.HSRelease hsRelease = null; 3025d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int anqpDomainID = 0; // No domain ID treated the same as a 0; unique info per AP. 3035d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 3045d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 3055d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 3065d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length >= 5 && data.getInt() == Constants.HS20_FRAME_PREFIX) { 3075d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int hsConf = data.get() & Constants.BYTE_MASK; 3085d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills switch ((hsConf >> 4) & Constants.NIBBLE_MASK) { 3095d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 0: 3105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R1; 3115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 3125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 1: 3135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R2; 3145d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 3155d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills default: 3165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.Unknown; 3175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 3185d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3195d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if ((hsConf & ANQP_DOMID_BIT) != 0) { 3205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length < 7) { 3215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException( 3225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills "HS20 indication element too short: " + ie.bytes.length); 3235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpDomainID = data.getShort() & Constants.SHORT_MASK; 3255d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 330b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 331b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * This IE contained a bit field indicating the capabilities being advertised by the STA. 332b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * The size of the bit field (number of bytes) is indicated by the |Length| field in the IE. 333b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 334b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Refer to Section 8.4.2.29 in IEEE 802.11-2012 Spec for capability associated with each 335b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * bit. 336b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 337b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Here is the wire format of this IE: 338b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * | Element ID | Length | Capabilities | 339b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 1 1 n 340b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 3415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class ExtendedCapabilities { 3425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int RTT_RESP_ENABLE_BIT = 70; 343b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu private static final int SSID_UTF8_BIT = 48; 3445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 345b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public BitSet capabilitiesBitSet; 3465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 347b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 348b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @return true if SSID should be interpreted using UTF-8 encoding 349b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 350b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public boolean isStrictUtf8() { 351b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu return capabilitiesBitSet.get(SSID_UTF8_BIT); 3525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 354b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 355b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @return true if 802.11 MC RTT Response is enabled 356b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 357b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public boolean is80211McRTTResponder() { 358b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu return capabilitiesBitSet.get(RTT_RESP_ENABLE_BIT); 3595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 361b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public ExtendedCapabilities() { 362b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = new BitSet(); 3635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 365b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public ExtendedCapabilities(ExtendedCapabilities other) { 366b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = other.capabilitiesBitSet; 367b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu } 3685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 369b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 370b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Parse an ExtendedCapabilities from the IE containing raw bytes. 371b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 372b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @param ie The Information element data 373b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 374b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public void from(InformationElement ie) { 375b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = BitSet.valueOf(ie.bytes); 3765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3783571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3793571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 3803571366ac36c70746b9f013ec2b54482861c9292Randy Pan * parse beacon to build the capabilities 3813571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 3823571366ac36c70746b9f013ec2b54482861c9292Randy Pan * This class is used to build the capabilities string of the scan results coming 3833571366ac36c70746b9f013ec2b54482861c9292Randy Pan * from HAL. It parses the ieee beacon's capability field, WPA and RSNE IE as per spec, 3843571366ac36c70746b9f013ec2b54482861c9292Randy Pan * and builds the ScanResult.capabilities String in a way that mirrors the values returned 3853571366ac36c70746b9f013ec2b54482861c9292Randy Pan * by wpa_supplicant. 3863571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 3873571366ac36c70746b9f013ec2b54482861c9292Randy Pan public static class Capabilities { 3889b5773d2805e8c6141ca75de272921a84941546bRandy Pan private static final int CAP_ESS_BIT_OFFSET = 0; 3893571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int CAP_PRIVACY_BIT_OFFSET = 4; 3903571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3913571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_VENDOR_OUI_TYPE_ONE = 0x01f25000; 392f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang private static final int WPS_VENDOR_OUI_TYPE = 0x04f25000; 3933571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short WPA_VENDOR_OUI_VERSION = 0x0001; 3943571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short RSNE_VERSION = 0x0001; 3953571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3963571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_EAP = 0x01f25000; 3973571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_PSK = 0x02f25000; 3983571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3993571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP = 0x01ac0f00; 4003571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK = 0x02ac0f00; 4013571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_EAP = 0x03ac0f00; 4023571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_PSK = 0x04ac0f00; 4033571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP_SHA256 = 0x05ac0f00; 4043571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK_SHA256 = 0x06ac0f00; 4053571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4064d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_NONE = 0x00f25000; 4074d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_TKIP = 0x02f25000; 4084d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_CCMP = 0x04f25000; 4094d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 4104d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_NONE = 0x00ac0f00; 4114d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_TKIP = 0x02ac0f00; 4124d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_CCMP = 0x04ac0f00; 4134d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_NO_GROUP_ADDRESSED = 0x07ac0f00; 4144d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 415c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<Integer> protocol; 416c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<ArrayList<Integer>> keyManagement; 417c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<ArrayList<Integer>> pairwiseCipher; 418c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang public ArrayList<Integer> groupCipher; 4194d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public boolean isESS; 4204d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public boolean isPrivacy; 421f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang public boolean isWPS; 4224d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 4233571366ac36c70746b9f013ec2b54482861c9292Randy Pan public Capabilities() { 4243571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4253571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4263571366ac36c70746b9f013ec2b54482861c9292Randy Pan // RSNE format (size unit: byte) 4273571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4283571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | Version | Group Data Cipher Suite | 4293571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 2 4 4303571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 4313571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 4323571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | RSN Capabilities | 4333571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 2 4343571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | PMKID Count | PMKID List | Group Management Cipher Suite | 4353571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 16 * s 4 4363571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4373571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 4383571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 4394d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private void parseRsnElement(InformationElement ie) { 4403571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 4413571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4423571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 4433571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 4443571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != RSNE_VERSION) { 4453571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 4464d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 4473571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4483571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4493571366ac36c70746b9f013ec2b54482861c9292Randy Pan // found the RSNE IE, hence start building the capability string 450c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang protocol.add(ScanResult.PROTOCOL_WPA2); 4514d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 4524d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // group data cipher suite 453c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang groupCipher.add(parseRsnCipher(buf.getInt())); 4543571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4553571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 4563571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 457c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> rsnPairwiseCipher = new ArrayList<>(); 4583571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite list 4593571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 460c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnPairwiseCipher.add(parseRsnCipher(buf.getInt())); 4613571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 462c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang pairwiseCipher.add(rsnPairwiseCipher); 4633571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4643571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 4653571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 4663571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 467c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> rsnKeyManagement = new ArrayList<>(); 4683571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4693571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 4703571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 4713571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 4723571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP: 473c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP); 4743571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4753571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK: 476c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_PSK); 4773571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4783571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_EAP: 479c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_FT_EAP); 4803571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4813571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_PSK: 482c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_FT_PSK); 4833571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4843571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP_SHA256: 485c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP_SHA256); 4863571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4873571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK_SHA256: 488c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_PSK_SHA256); 4893571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4903571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 4913571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 4923571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4933571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4943571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4954d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // Default AKM 496c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang if (rsnKeyManagement.isEmpty()) { 497c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP); 4984d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 499c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang keyManagement.add(rsnKeyManagement); 5003571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 5013571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse RSNE, buffer underflow"); 5024d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5034d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5044d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 505fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private static int parseWpaCipher(int cipher) { 5064d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang switch (cipher) { 5074d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_NONE: 508fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5094d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_TKIP: 510fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_TKIP; 5114d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_CCMP: 512fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_CCMP; 5134d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang default: 514fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang Log.w("IE_Capabilities", "Unknown WPA cipher suite: " 515fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + Integer.toHexString(cipher)); 516fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5174d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5184d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5194d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 520fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private static int parseRsnCipher(int cipher) { 5214d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang switch (cipher) { 5224d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_NONE: 523fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5244d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_TKIP: 525fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_TKIP; 5264d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_CCMP: 527fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_CCMP; 5284d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_NO_GROUP_ADDRESSED: 529fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NO_GROUP_ADDRESSED; 5304d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang default: 531fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang Log.w("IE_Capabilities", "Unknown RSN cipher suite: " 532fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + Integer.toHexString(cipher)); 533fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 5343571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5353571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5363571366ac36c70746b9f013ec2b54482861c9292Randy Pan 537f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang private static boolean isWpsElement(InformationElement ie) { 538f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 539f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang try { 540f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang // WPS OUI and type 541f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang return (buf.getInt() == WPS_VENDOR_OUI_TYPE); 542f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } catch (BufferUnderflowException e) { 543f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang Log.e("IE_Capabilities", "Couldn't parse VSA IE, buffer underflow"); 544f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang return false; 545f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 546f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 547f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang 5483571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static boolean isWpaOneElement(InformationElement ie) { 5493571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 5503571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5513571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 5523571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA OUI and type 5533571366ac36c70746b9f013ec2b54482861c9292Randy Pan return (buf.getInt() == WPA_VENDOR_OUI_TYPE_ONE); 5543571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 5553571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse VSA IE, buffer underflow"); 5563571366ac36c70746b9f013ec2b54482861c9292Randy Pan return false; 5573571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5583571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5593571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5603571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA type 1 format (size unit: byte) 5613571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 5623571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | OUI | Type | Version | 5633571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 3 1 2 5644d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // | Group Data Cipher Suite | 5654d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // 4 5663571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 5673571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 5683571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | 5693571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 5703571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 5713571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 5723571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 5733571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 5744d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private void parseWpaOneElement(InformationElement ie) { 5753571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 5763571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5773571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 5783571366ac36c70746b9f013ec2b54482861c9292Randy Pan // skip WPA OUI and type parsing. isWpaOneElement() should have 5793571366ac36c70746b9f013ec2b54482861c9292Randy Pan // been called for verification before we reach here. 5803571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 5813571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5823571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 5833571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != WPA_VENDOR_OUI_VERSION) { 5843571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 5854d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 5863571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5873571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5884d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // start building the string 589c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang protocol.add(ScanResult.PROTOCOL_WPA); 5904d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 5913571366ac36c70746b9f013ec2b54482861c9292Randy Pan // group data cipher suite 592c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang groupCipher.add(parseWpaCipher(buf.getInt())); 5933571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5943571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 5953571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 596c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> wpaPairwiseCipher = new ArrayList<>(); 5973571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise chipher suite list 5983571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 599c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaPairwiseCipher.add(parseWpaCipher(buf.getInt())); 6003571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 601c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang pairwiseCipher.add(wpaPairwiseCipher); 6023571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6033571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 6043571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 6053571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 606c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang ArrayList<Integer> wpaKeyManagement = new ArrayList<>(); 6073571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6083571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite list 6093571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 6103571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 6113571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 6123571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_EAP: 613c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaKeyManagement.add(ScanResult.KEY_MGMT_EAP); 6143571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 6153571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_PSK: 616c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaKeyManagement.add(ScanResult.KEY_MGMT_PSK); 6173571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 6183571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 6193571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 6203571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 6213571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6223571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6234d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // Default AKM 624c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang if (wpaKeyManagement.isEmpty()) { 625c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang wpaKeyManagement.add(ScanResult.KEY_MGMT_EAP); 6264d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 627c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang keyManagement.add(wpaKeyManagement); 6283571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 6293571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse type 1 WPA, buffer underflow"); 6303571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6313571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6323571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6333571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 6343571366ac36c70746b9f013ec2b54482861c9292Randy Pan * Parse the Information Element and the 16-bit Capability Information field 6354d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * to build the InformationElemmentUtil.capabilities object. 6363571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 6373571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param ies -- Information Element array 6383571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param beaconCap -- 16-bit Beacon Capability Information field 6393571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 6404d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 6414d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public void from(InformationElement[] ies, BitSet beaconCap) { 642c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang protocol = new ArrayList<Integer>(); 643c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang keyManagement = new ArrayList<ArrayList<Integer>>(); 644c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang groupCipher = new ArrayList<Integer>(); 645c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang pairwiseCipher = new ArrayList<ArrayList<Integer>>(); 6463571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6473571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ies == null || beaconCap == null) { 6484d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 6493571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6504d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang isESS = beaconCap.get(CAP_ESS_BIT_OFFSET); 6514d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang isPrivacy = beaconCap.get(CAP_PRIVACY_BIT_OFFSET); 6523571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (InformationElement ie : ies) { 6533571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_RSN) { 6544d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang parseRsnElement(ie); 6553571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6563571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6573571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_VSA) { 6583571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (isWpaOneElement(ie)) { 6594d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang parseWpaOneElement(ie); 6603571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 661f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang if (isWpsElement(ie)) { 662f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang // TODO(b/62134557): parse WPS IE to provide finer granularity information. 663f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang isWPS = true; 664f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 6653571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6663571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 667fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 668fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 669fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String protocolToString(int protocol) { 670fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (protocol) { 671fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_NONE: 672fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 673fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_WPA: 674fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "WPA"; 675fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_WPA2: 676fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "WPA2"; 677fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 678fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 679fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 680fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 681fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 682fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String keyManagementToString(int akm) { 683fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (akm) { 684fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_NONE: 685fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 686fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_PSK: 687fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "PSK"; 688fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_EAP: 689fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "EAP"; 690fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_FT_EAP: 691fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "FT/EAP"; 692fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_FT_PSK: 693fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "FT/PSK"; 694fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_EAP_SHA256: 695fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "EAP-SHA256"; 696fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_PSK_SHA256: 697fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "PSK-SHA256"; 698fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 699fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 700fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 701fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 702fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 703fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String cipherToString(int cipher) { 704fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (cipher) { 705fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_NONE: 706fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 707fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_CCMP: 708fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "CCMP"; 709fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_TKIP: 710fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "TKIP"; 711fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 712fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 7133571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 7144d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 7153571366ac36c70746b9f013ec2b54482861c9292Randy Pan 7164d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang /** 7174d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * Build the ScanResult.capabilities String. 7184d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * 7194d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * @return security string that mirrors what wpa_supplicant generates 7204d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang */ 7214d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public String generateCapabilitiesString() { 7224d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang String capabilities = ""; 723fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang // private Beacon without an RSNE or WPA IE, hence WEP0 724c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang boolean isWEP = (protocol.isEmpty()) && isPrivacy; 725fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 726c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang if (isWEP) { 727c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang capabilities += "[WEP]"; 728c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang } 729c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang for (int i = 0; i < protocol.size(); i++) { 730c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang capabilities += "[" + protocolToString(protocol.get(i)); 731c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang for (int j = 0; j < keyManagement.get(i).size(); j++) { 732c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang capabilities += ((j == 0) ? "-" : "+") 733c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang + keyManagementToString(keyManagement.get(i).get(j)); 7344d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 735c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang for (int j = 0; j < pairwiseCipher.get(i).size(); j++) { 736c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang capabilities += ((j == 0) ? "-" : "+") 737c66d00cefbd32ec2fbefcf1fd54c1aaf50b5ce5aNingyuan Wang + cipherToString(pairwiseCipher.get(i).get(j)); 7384d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 7394d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang capabilities += "]"; 7404d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 7414d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang if (isESS) { 7429b5773d2805e8c6141ca75de272921a84941546bRandy Pan capabilities += "[ESS]"; 7439b5773d2805e8c6141ca75de272921a84941546bRandy Pan } 744f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang if (isWPS) { 745f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang capabilities += "[WPS]"; 746f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang } 747f7364b4baea06722022b7c6519ace0556481cc06Ningyuan Wang 7483571366ac36c70746b9f013ec2b54482861c9292Randy Pan return capabilities; 7493571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 7503571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 751947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 752947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 753947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Parser for the Traffic Indication Map (TIM) Information Element (EID 5). This element will 754947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * only be present in scan results that are derived from a Beacon Frame, not from the more 755947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * plentiful probe responses. Call 'isValid()' after parsing, to ensure the results are correct. 756947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 757947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public static class TrafficIndicationMap { 758947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private static final int MAX_TIM_LENGTH = 254; 759947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private boolean mValid = false; 760947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mLength = 0; 761947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimCount = -1; 762947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //Negative DTIM Period means no TIM element was given this frame. 763947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimPeriod = -1; 764947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mBitmapControl = 0; 765947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 766947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 767947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Is this a valid TIM information element. 768947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 769947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public boolean isValid() { 770947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return mValid; 771947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 772947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 773947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Traffic Indication Map format (size unit: byte) 774947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 775947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //| ElementID | Length | DTIM Count | DTIM Period | BitmapControl | Partial Virtual Bitmap | 776947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 1 1 1 1 1 1 - 251 777947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 778947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 779947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // stripped off already 780947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 781947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public void from(InformationElement ie) { 782e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 783947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne if (ie == null || ie.bytes == null) return; 784947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mLength = ie.bytes.length; 785947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 786947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne try { 787947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimCount = data.get() & Constants.BYTE_MASK; 788947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimPeriod = data.get() & Constants.BYTE_MASK; 789947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mBitmapControl = data.get() & Constants.BYTE_MASK; 790947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //A valid TIM element must have atleast one more byte 791947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne data.get(); 792947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } catch (BufferUnderflowException e) { 793947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return; 794947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 79559f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne if (mLength <= MAX_TIM_LENGTH && mDtimPeriod > 0) { 796947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mValid = true; 797947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 798947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 799947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 800f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 801f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 802f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * This util class determines the 802.11 standard (a/b/g/n/ac) being used 803f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 804f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class WifiMode { 805f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_UNDEFINED = 0; // Unknown/undefined 806f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11A = 1; // 802.11a 807f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11B = 2; // 802.11b 808f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11G = 3; // 802.11g 809f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11N = 4; // 802.11n 810f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11AC = 5; // 802.11ac 811f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //<TODO> add support for 802.11ad and be more selective instead of defaulting to 11A 812f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 813f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 814f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Use frequency, max supported rate, and the existence of VHT, HT & ERP fields in scan 815f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * scan result to determine the 802.11 Wifi standard being used. 816f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 817f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int determineMode(int frequency, int maxRate, boolean foundVht, 818f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne boolean foundHt, boolean foundErp) { 819f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (foundVht) { 820f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11AC; 821f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundHt) { 822f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11N; 823f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundErp) { 824f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 825f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (frequency < 3000) { 826f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (maxRate < 24000000) { 827f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11B; 828f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 829f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 830f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 831f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 832f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11A; 833f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 834f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 835f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 836f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 837f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Map the wifiMode integer to its type, and output as String MODE_11<A/B/G/N/AC> 838f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 839f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static String toString(int mode) { 840f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(mode) { 841f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11A: 842f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11A"; 843f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11B: 844f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11B"; 845f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11G: 846f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11G"; 847f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11N: 848f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11N"; 849f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11AC: 850f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11AC"; 851f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 852f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_UNDEFINED"; 853f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 854f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 855f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 856f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 857f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 858f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Parser for both the Supported Rates & Extended Supported Rates Information Elements 859f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 860f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class SupportedRates { 861f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MASK = 0x7F; // 0111 1111 862f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean mValid = false; 863f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public ArrayList<Integer> mRates; 864f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 865f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public SupportedRates() { 866f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates = new ArrayList<Integer>(); 867f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 868f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 869f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 870f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Is this a valid Supported Rates information element. 871f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 872f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean isValid() { 873f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return mValid; 874f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 875f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 876f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 877f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * get the Rate in bits/s from associated byteval 878f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 879f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int getRateFromByte(int byteVal) { 880f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne byteVal &= MASK; 881f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(byteVal) { 882f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 2: 883f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 1000000; 884f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 4: 885f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 2000000; 886f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 11: 887f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 5500000; 888f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 12: 889f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 6000000; 890f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 18: 891f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 9000000; 892f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 22: 893f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 11000000; 894f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 24: 895f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 12000000; 896f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 36: 897f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 18000000; 898f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 44: 899f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 22000000; 900f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 48: 901f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 24000000; 902f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 66: 903f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 33000000; 904f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 72: 905f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 36000000; 906f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 96: 907f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 48000000; 908f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 108: 909f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 54000000; 910f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 911f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //ERROR UNKNOWN RATE 912f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return -1; 913f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 914f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 915f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 916f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Supported Rates format (size unit: byte) 917f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 918f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //| ElementID | Length | Supported Rates [7 Little Endian Info bits - 1 Flag bit] 919f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 1 1 1 - 8 920f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 921f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 922f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // stripped off already 923f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 924f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public void from(InformationElement ie) { 925e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 926e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart if (ie == null || ie.bytes == null || ie.bytes.length > 8 || ie.bytes.length < 1) { 927f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 928f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 929f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 930f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne try { 931f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (int i = 0; i < ie.bytes.length; i++) { 932f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne int rate = getRateFromByte(data.get()); 933f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (rate > 0) { 934f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates.add(rate); 935f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 936f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 937f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 938f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 939f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } catch (BufferUnderflowException e) { 940f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 941f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 942f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mValid = true; 943f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 944f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 945f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 946f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 947f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Lists the rates in a human readable string 948f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 949f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public String toString() { 950f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne StringBuilder sbuf = new StringBuilder(); 951f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (Integer rate : mRates) { 952f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne sbuf.append(String.format("%.1f", (double) rate / 1000000) + ", "); 953f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 954f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return sbuf.toString(); 955f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 956f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 9575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills} 958