InformationElementUtil.java revision fa04a81daf829e6e5c099c9a249b8dd8dd112102
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 { 335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static InformationElement[] parseInformationElements(byte[] bytes) { 35da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein if (bytes == null) { 36da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein return new InformationElement[0]; 37da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein } 385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); 395d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 405d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ArrayList<InformationElement> infoElements = new ArrayList<>(); 415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills boolean found_ssid = false; 425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills while (data.remaining() > 1) { 435d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int eid = data.get() & Constants.BYTE_MASK; 445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int elementLength = data.get() & Constants.BYTE_MASK; 455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 463571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (elementLength > data.remaining() || (eid == InformationElement.EID_SSID 473571366ac36c70746b9f013ec2b54482861c9292Randy Pan && found_ssid)) { 48da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // APs often pad the data with bytes that happen to match that of the EID_SSID 49da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // marker. This is not due to a known issue for APs to incorrectly send the SSID 50da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // name multiple times. 515d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 533571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (eid == InformationElement.EID_SSID) { 545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills found_ssid = true; 555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills InformationElement ie = new InformationElement(); 585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ie.id = eid; 595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ie.bytes = new byte[elementLength]; 605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills data.get(ie.bytes); 615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills infoElements.add(ie); 625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return infoElements.toArray(new InformationElement[infoElements.size()]); 645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class BssLoad { 685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int stationCount = 0; 695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int channelUtilization = 0; 705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int capacity = 0; 715d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 733571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_BSS_LOAD) { 745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not BSS_LOAD, : " + ie.id); 755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length != 5) { 773571366ac36c70746b9f013ec2b54482861c9292Randy Pan throw new IllegalArgumentException("BSS Load element length is not 5: " 783571366ac36c70746b9f013ec2b54482861c9292Randy Pan + ie.bytes.length); 795d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills stationCount = data.getShort() & Constants.SHORT_MASK; 825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills channelUtilization = data.get() & Constants.BYTE_MASK; 835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills capacity = data.getShort() & Constants.SHORT_MASK; 845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class HtOperation { 885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int secondChannelOffset = 0; 895d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 905d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getChannelWidth() { 913571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (secondChannelOffset != 0) { 925d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 1; 933571366ac36c70746b9f013ec2b54482861c9292Randy Pan } else { 945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 955d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 965d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 975d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 985d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq0(int primaryFrequency) { 999f743918a412fec9ad5a0386fbf6cf0361313f58xinhe //40 MHz 1009f743918a412fec9ad5a0386fbf6cf0361313f58xinhe if (secondChannelOffset != 0) { 1015d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (secondChannelOffset == 1) { 1029f743918a412fec9ad5a0386fbf6cf0361313f58xinhe return primaryFrequency + 10; 1035d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else if (secondChannelOffset == 3) { 1049f743918a412fec9ad5a0386fbf6cf0361313f58xinhe return primaryFrequency - 10; 1055d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 1065d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills Log.e("HtOperation", "Error on secondChannelOffset: " + secondChannelOffset); 1075d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1085d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1095d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 1105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1145d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1153571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_HT_OPERATION) { 1165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not HT_OPERATION, : " + ie.id); 1175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1185d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills secondChannelOffset = ie.bytes[1] & 0x3; 1195d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class VhtOperation { 1235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int channelMode = 0; 1245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int centerFreqIndex1 = 0; 1255d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int centerFreqIndex2 = 0; 1265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean isValid() { 1285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return channelMode != 0; 1295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1305d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getChannelWidth() { 1325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return channelMode + 1; 1335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq0() { 1365d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills //convert channel index to frequency in MHz, channel 36 is 5180MHz 1375d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return (centerFreqIndex1 - 36) * 5 + 5180; 1385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1395d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1405d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq1() { 1413571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (channelMode > 1) { //160MHz 1425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return (centerFreqIndex2 - 36) * 5 + 5180; 1435d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 1445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1475d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1485d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1493571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_VHT_OPERATION) { 1505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not VHT_OPERATION, : " + ie.id); 1515d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills channelMode = ie.bytes[0] & Constants.BYTE_MASK; 1535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills centerFreqIndex1 = ie.bytes[1] & Constants.BYTE_MASK; 1545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills centerFreqIndex2 = ie.bytes[2] & Constants.BYTE_MASK; 1555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class Interworking { 1595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public NetworkDetail.Ant ant = null; 1605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean internet = false; 1615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public long hessid = 0L; 1625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1643571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_INTERWORKING) { 1655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not INTERWORKING, : " + ie.id); 1665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 1685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int anOptions = data.get() & Constants.BYTE_MASK; 1695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ant = NetworkDetail.Ant.values()[anOptions & 0x0f]; 1705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills internet = (anOptions & 0x10) != 0; 171e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // There are only three possible lengths for the Interworking IE: 172e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 1: Access Network Options only 173e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 3: Access Network Options & Venue Info 174e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 7: Access Network Options & HESSID 175e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 9: Access Network Options, Venue Info, & HESSID 176e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan if (ie.bytes.length != 1 177e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan && ie.bytes.length != 3 178e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan && ie.bytes.length != 7 179e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan && ie.bytes.length != 9) { 180e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan throw new IllegalArgumentException( 181e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan "Bad Interworking element length: " + ie.bytes.length); 1825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 183e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan 1845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length == 7 || ie.bytes.length == 9) { 185fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu hessid = ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, 6); 1865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1895d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1905d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class RoamingConsortium { 1915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int anqpOICount = 0; 1925d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public long[] roamingConsortiums = null; 1935d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1953571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_ROAMING_CONSORTIUM) { 1963571366ac36c70746b9f013ec2b54482861c9292Randy Pan throw new IllegalArgumentException("Element id is not ROAMING_CONSORTIUM, : " 1973571366ac36c70746b9f013ec2b54482861c9292Randy Pan + ie.id); 1985d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1995d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2005d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpOICount = data.get() & Constants.BYTE_MASK; 2015d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2025d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi12Length = data.get() & Constants.BYTE_MASK; 2035d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi1Length = oi12Length & Constants.NIBBLE_MASK; 2045d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi2Length = (oi12Length >>> 4) & Constants.NIBBLE_MASK; 2055d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi3Length = ie.bytes.length - 2 - oi1Length - oi2Length; 2065d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oiCount = 0; 2075d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0) { 2085d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2095d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0) { 2105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0) { 2125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2145d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2155d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums = new long[oiCount]; 2175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0 && roamingConsortiums.length > 0) { 2185d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[0] = 219fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi1Length); 2205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0 && roamingConsortiums.length > 1) { 2225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[1] = 223fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi2Length); 2245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2255d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0 && roamingConsortiums.length > 2) { 2265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[2] = 227fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, oi3Length); 2285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2305d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class Vsa { 2335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int ANQP_DOMID_BIT = 0x04; 2345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public NetworkDetail.HSRelease hsRelease = null; 2365d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int anqpDomainID = 0; // No domain ID treated the same as a 0; unique info per AP. 2375d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2395d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2405d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length >= 5 && data.getInt() == Constants.HS20_FRAME_PREFIX) { 2415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int hsConf = data.get() & Constants.BYTE_MASK; 2425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills switch ((hsConf >> 4) & Constants.NIBBLE_MASK) { 2435d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 0: 2445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R1; 2455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 2465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 1: 2475d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R2; 2485d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 2495d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills default: 2505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.Unknown; 2515d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 2525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if ((hsConf & ANQP_DOMID_BIT) != 0) { 2545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length < 7) { 2555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException( 2565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills "HS20 indication element too short: " + ie.bytes.length); 2575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpDomainID = data.getShort() & Constants.SHORT_MASK; 2595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class ExtendedCapabilities { 2655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int RTT_RESP_ENABLE_BIT = 70; 2665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final long SSID_UTF8_BIT = 0x0001000000000000L; 2675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public Long extendedCapabilities = null; 2695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean is80211McRTTResponder = false; 2705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2715d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public ExtendedCapabilities() { 2725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2735d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public ExtendedCapabilities(ExtendedCapabilities other) { 2755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills extendedCapabilities = other.extendedCapabilities; 2765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills is80211McRTTResponder = other.is80211McRTTResponder; 2775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2795d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean isStrictUtf8() { 2805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return extendedCapabilities != null && (extendedCapabilities & SSID_UTF8_BIT) != 0; 2815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills extendedCapabilities = 286fa04a81daf829e6e5c099c9a249b8dd8dd112102Peter Qiu ByteBufferReader.readInteger(data, ByteOrder.LITTLE_ENDIAN, ie.bytes.length); 2875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int index = RTT_RESP_ENABLE_BIT / 8; 2895d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills byte offset = RTT_RESP_ENABLE_BIT % 8; 2903571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.bytes.length < index + 1) { 2915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills is80211McRTTResponder = false; 2925d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 2933571366ac36c70746b9f013ec2b54482861c9292Randy Pan is80211McRTTResponder = (ie.bytes[index] & ((byte) 0x1 << offset)) != 0; 2945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2955d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2965d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2973571366ac36c70746b9f013ec2b54482861c9292Randy Pan 2983571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 2993571366ac36c70746b9f013ec2b54482861c9292Randy Pan * parse beacon to build the capabilities 3003571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 3013571366ac36c70746b9f013ec2b54482861c9292Randy Pan * This class is used to build the capabilities string of the scan results coming 3023571366ac36c70746b9f013ec2b54482861c9292Randy Pan * from HAL. It parses the ieee beacon's capability field, WPA and RSNE IE as per spec, 3033571366ac36c70746b9f013ec2b54482861c9292Randy Pan * and builds the ScanResult.capabilities String in a way that mirrors the values returned 3043571366ac36c70746b9f013ec2b54482861c9292Randy Pan * by wpa_supplicant. 3053571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 3063571366ac36c70746b9f013ec2b54482861c9292Randy Pan public static class Capabilities { 3079b5773d2805e8c6141ca75de272921a84941546bRandy Pan private static final int CAP_ESS_BIT_OFFSET = 0; 3083571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int CAP_PRIVACY_BIT_OFFSET = 4; 3093571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3103571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_VENDOR_OUI_TYPE_ONE = 0x01f25000; 3113571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short WPA_VENDOR_OUI_VERSION = 0x0001; 3123571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short RSNE_VERSION = 0x0001; 3133571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3143571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_EAP = 0x01f25000; 3153571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_PSK = 0x02f25000; 3163571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3173571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP = 0x01ac0f00; 3183571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK = 0x02ac0f00; 3193571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_EAP = 0x03ac0f00; 3203571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_PSK = 0x04ac0f00; 3213571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP_SHA256 = 0x05ac0f00; 3223571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK_SHA256 = 0x06ac0f00; 3233571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3244d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_NONE = 0x00f25000; 3254d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_TKIP = 0x02f25000; 3264d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_CCMP = 0x04f25000; 3274d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 3284d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_NONE = 0x00ac0f00; 3294d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_TKIP = 0x02ac0f00; 3304d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_CCMP = 0x04ac0f00; 3314d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_NO_GROUP_ADDRESSED = 0x07ac0f00; 3324d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 333fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang public int protocol; 334fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang public ArrayList<Integer> keyManagement; 335fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang public ArrayList<Integer> pairwiseCipher; 336fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang public int groupCipher; 3374d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public boolean isESS; 3384d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public boolean isPrivacy; 3394d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 3403571366ac36c70746b9f013ec2b54482861c9292Randy Pan public Capabilities() { 3413571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3423571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3433571366ac36c70746b9f013ec2b54482861c9292Randy Pan // RSNE format (size unit: byte) 3443571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 3453571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | Version | Group Data Cipher Suite | 3463571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 2 4 3473571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 3483571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 3493571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | RSN Capabilities | 3503571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 2 3513571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | PMKID Count | PMKID List | Group Management Cipher Suite | 3523571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 16 * s 4 3533571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 3543571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 3553571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 3564d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private void parseRsnElement(InformationElement ie) { 3573571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 3583571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3593571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 3603571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 3613571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != RSNE_VERSION) { 3623571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 3634d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 3643571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3653571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3663571366ac36c70746b9f013ec2b54482861c9292Randy Pan // found the RSNE IE, hence start building the capability string 367fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang protocol = ScanResult.PROTOCOL_WPA2; 3684d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 3694d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // group data cipher suite 370fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang groupCipher = parseRsnCipher(buf.getInt()); 3713571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3723571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 3733571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 3743571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite list 3753571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 376fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang pairwiseCipher.add(parseRsnCipher(buf.getInt())); 3773571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3783571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3793571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 3803571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 3813571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 3823571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3833571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 3843571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 3853571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 3863571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP: 387fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_EAP); 3883571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3893571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK: 390fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_PSK); 3913571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3923571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_EAP: 393fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_FT_EAP); 3943571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3953571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_PSK: 396fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_FT_PSK); 3973571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3983571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP_SHA256: 399fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_EAP_SHA256); 4003571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4013571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK_SHA256: 402fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_PSK_SHA256); 4033571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4043571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 4053571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 4063571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4073571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4083571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4094d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // Default AKM 4104d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang if (keyManagement.isEmpty()) { 411fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_EAP); 4124d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 4133571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 4143571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse RSNE, buffer underflow"); 4154d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 4164d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 4174d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 418fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private static int parseWpaCipher(int cipher) { 4194d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang switch (cipher) { 4204d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_NONE: 421fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 4224d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_TKIP: 423fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_TKIP; 4244d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_CCMP: 425fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_CCMP; 4264d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang default: 427fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang Log.w("IE_Capabilities", "Unknown WPA cipher suite: " 428fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + Integer.toHexString(cipher)); 429fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 4304d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 4314d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 4324d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 433fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private static int parseRsnCipher(int cipher) { 4344d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang switch (cipher) { 4354d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_NONE: 436fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 4374d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_TKIP: 438fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_TKIP; 4394d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_CCMP: 440fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_CCMP; 4414d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_NO_GROUP_ADDRESSED: 442fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NO_GROUP_ADDRESSED; 4434d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang default: 444fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang Log.w("IE_Capabilities", "Unknown RSN cipher suite: " 445fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + Integer.toHexString(cipher)); 446fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 4473571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4483571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4493571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4503571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static boolean isWpaOneElement(InformationElement ie) { 4513571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 4523571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4533571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 4543571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA OUI and type 4553571366ac36c70746b9f013ec2b54482861c9292Randy Pan return (buf.getInt() == WPA_VENDOR_OUI_TYPE_ONE); 4563571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 4573571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse VSA IE, buffer underflow"); 4583571366ac36c70746b9f013ec2b54482861c9292Randy Pan return false; 4593571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4603571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4613571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4623571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA type 1 format (size unit: byte) 4633571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4643571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | OUI | Type | Version | 4653571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 3 1 2 4664d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // | Group Data Cipher Suite | 4674d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // 4 4683571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 4693571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 4703571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | 4713571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 4723571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4733571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 4743571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 4753571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4764d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private void parseWpaOneElement(InformationElement ie) { 4773571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 4783571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4793571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 4803571366ac36c70746b9f013ec2b54482861c9292Randy Pan // skip WPA OUI and type parsing. isWpaOneElement() should have 4813571366ac36c70746b9f013ec2b54482861c9292Randy Pan // been called for verification before we reach here. 4823571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 4833571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4843571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 4853571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != WPA_VENDOR_OUI_VERSION) { 4863571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 4874d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 4883571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4893571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4904d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // start building the string 491fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang protocol = ScanResult.PROTOCOL_WPA; 4924d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 4933571366ac36c70746b9f013ec2b54482861c9292Randy Pan // group data cipher suite 494fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang groupCipher = parseWpaCipher(buf.getInt()); 4953571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4963571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 4973571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 4983571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise chipher suite list 4993571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 500fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang pairwiseCipher.add(parseWpaCipher(buf.getInt())); 5013571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5023571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5033571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 5043571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 5053571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 5063571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5073571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite list 5083571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 5093571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 5103571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 5113571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_EAP: 512fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_EAP); 5133571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 5143571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_PSK: 515fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_PSK); 5163571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 5173571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 5183571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 5193571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 5203571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5213571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5224d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // Default AKM 5234d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang if (keyManagement.isEmpty()) { 524fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_EAP); 5254d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5263571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 5273571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse type 1 WPA, buffer underflow"); 5283571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5293571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5303571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5313571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 5323571366ac36c70746b9f013ec2b54482861c9292Randy Pan * Parse the Information Element and the 16-bit Capability Information field 5334d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * to build the InformationElemmentUtil.capabilities object. 5343571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 5353571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param ies -- Information Element array 5363571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param beaconCap -- 16-bit Beacon Capability Information field 5373571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 5384d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 5394d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public void from(InformationElement[] ies, BitSet beaconCap) { 540fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang protocol = ScanResult.PROTOCOL_NONE; 541fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement = new ArrayList<Integer>(); 542fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang groupCipher = ScanResult.CIPHER_NONE; 543fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang pairwiseCipher = new ArrayList<Integer>(); 5443571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean rsneFound = false; 5453571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean wpaFound = false; 5463571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5473571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ies == null || beaconCap == null) { 5484d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 5493571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5504d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang isESS = beaconCap.get(CAP_ESS_BIT_OFFSET); 5514d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang isPrivacy = beaconCap.get(CAP_PRIVACY_BIT_OFFSET); 5523571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (InformationElement ie : ies) { 5533571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_RSN) { 5543571366ac36c70746b9f013ec2b54482861c9292Randy Pan rsneFound = true; 5554d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang parseRsnElement(ie); 5563571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5573571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5583571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_VSA) { 5593571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (isWpaOneElement(ie)) { 5603571366ac36c70746b9f013ec2b54482861c9292Randy Pan wpaFound = true; 5614d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang parseWpaOneElement(ie); 5623571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5633571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5643571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 565fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 566fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 567fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String protocolToString(int protocol) { 568fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (protocol) { 569fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_NONE: 570fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 571fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_WPA: 572fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "WPA"; 573fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_WPA2: 574fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "WPA2"; 575fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 576fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 577fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 578fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 579fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 580fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String keyManagementToString(int akm) { 581fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (akm) { 582fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_NONE: 583fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 584fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_PSK: 585fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "PSK"; 586fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_EAP: 587fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "EAP"; 588fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_FT_EAP: 589fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "FT/EAP"; 590fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_FT_PSK: 591fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "FT/PSK"; 592fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_EAP_SHA256: 593fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "EAP-SHA256"; 594fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_PSK_SHA256: 595fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "PSK-SHA256"; 596fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 597fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 598fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 599fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 600fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 601fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String cipherToString(int cipher) { 602fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (cipher) { 603fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_NONE: 604fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 605fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_CCMP: 606fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "CCMP"; 607fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_TKIP: 608fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "TKIP"; 609fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 610fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 6113571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6124d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 6133571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6144d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang /** 6154d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * Build the ScanResult.capabilities String. 6164d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * 6174d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * @return security string that mirrors what wpa_supplicant generates 6184d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang */ 6194d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public String generateCapabilitiesString() { 6204d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang String capabilities = ""; 621fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang // private Beacon without an RSNE or WPA IE, hence WEP0 622fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang boolean isWEP = (protocol == ScanResult.PROTOCOL_NONE) && isPrivacy; 623fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 624fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang if (protocol != ScanResult.PROTOCOL_NONE || isWEP) { 625fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang capabilities += "[" + (isWEP ? "WEP" : protocolToString(protocol)); 6264d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang for (int i = 0; i < keyManagement.size(); i++) { 627fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang capabilities += ((i == 0) ? "-" : "+") 628fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + keyManagementToString(keyManagement.get(i)); 6294d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 6304d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang for (int i = 0; i < pairwiseCipher.size(); i++) { 631fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang capabilities += ((i == 0) ? "-" : "+") + cipherToString(pairwiseCipher.get(i)); 6324d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 6334d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang capabilities += "]"; 6344d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 6354d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang if (isESS) { 6369b5773d2805e8c6141ca75de272921a84941546bRandy Pan capabilities += "[ESS]"; 6379b5773d2805e8c6141ca75de272921a84941546bRandy Pan } 6383571366ac36c70746b9f013ec2b54482861c9292Randy Pan return capabilities; 6393571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6403571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 641947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 642947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 643947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Parser for the Traffic Indication Map (TIM) Information Element (EID 5). This element will 644947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * only be present in scan results that are derived from a Beacon Frame, not from the more 645947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * plentiful probe responses. Call 'isValid()' after parsing, to ensure the results are correct. 646947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 647947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public static class TrafficIndicationMap { 648947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private static final int MAX_TIM_LENGTH = 254; 649947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private boolean mValid = false; 650947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mLength = 0; 651947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimCount = -1; 652947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //Negative DTIM Period means no TIM element was given this frame. 653947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimPeriod = -1; 654947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mBitmapControl = 0; 655947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 656947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 657947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Is this a valid TIM information element. 658947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 659947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public boolean isValid() { 660947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return mValid; 661947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 662947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 663947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Traffic Indication Map format (size unit: byte) 664947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 665947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //| ElementID | Length | DTIM Count | DTIM Period | BitmapControl | Partial Virtual Bitmap | 666947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 1 1 1 1 1 1 - 251 667947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 668947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 669947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // stripped off already 670947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 671947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public void from(InformationElement ie) { 672e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 673947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne if (ie == null || ie.bytes == null) return; 674947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mLength = ie.bytes.length; 675947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 676947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne try { 677947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimCount = data.get() & Constants.BYTE_MASK; 678947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimPeriod = data.get() & Constants.BYTE_MASK; 679947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mBitmapControl = data.get() & Constants.BYTE_MASK; 680947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //A valid TIM element must have atleast one more byte 681947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne data.get(); 682947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } catch (BufferUnderflowException e) { 683947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return; 684947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 68559f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne if (mLength <= MAX_TIM_LENGTH && mDtimPeriod > 0) { 686947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mValid = true; 687947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 688947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 689947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 690f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 691f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 692f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * This util class determines the 802.11 standard (a/b/g/n/ac) being used 693f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 694f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class WifiMode { 695f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_UNDEFINED = 0; // Unknown/undefined 696f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11A = 1; // 802.11a 697f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11B = 2; // 802.11b 698f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11G = 3; // 802.11g 699f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11N = 4; // 802.11n 700f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11AC = 5; // 802.11ac 701f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //<TODO> add support for 802.11ad and be more selective instead of defaulting to 11A 702f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 703f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 704f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Use frequency, max supported rate, and the existence of VHT, HT & ERP fields in scan 705f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * scan result to determine the 802.11 Wifi standard being used. 706f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 707f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int determineMode(int frequency, int maxRate, boolean foundVht, 708f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne boolean foundHt, boolean foundErp) { 709f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (foundVht) { 710f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11AC; 711f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundHt) { 712f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11N; 713f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundErp) { 714f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 715f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (frequency < 3000) { 716f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (maxRate < 24000000) { 717f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11B; 718f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 719f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 720f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 721f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 722f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11A; 723f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 724f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 725f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 726f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 727f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Map the wifiMode integer to its type, and output as String MODE_11<A/B/G/N/AC> 728f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 729f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static String toString(int mode) { 730f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(mode) { 731f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11A: 732f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11A"; 733f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11B: 734f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11B"; 735f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11G: 736f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11G"; 737f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11N: 738f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11N"; 739f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11AC: 740f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11AC"; 741f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 742f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_UNDEFINED"; 743f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 744f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 745f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 746f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 747f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 748f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Parser for both the Supported Rates & Extended Supported Rates Information Elements 749f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 750f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class SupportedRates { 751f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MASK = 0x7F; // 0111 1111 752f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean mValid = false; 753f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public ArrayList<Integer> mRates; 754f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 755f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public SupportedRates() { 756f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates = new ArrayList<Integer>(); 757f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 758f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 759f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 760f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Is this a valid Supported Rates information element. 761f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 762f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean isValid() { 763f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return mValid; 764f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 765f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 766f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 767f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * get the Rate in bits/s from associated byteval 768f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 769f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int getRateFromByte(int byteVal) { 770f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne byteVal &= MASK; 771f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(byteVal) { 772f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 2: 773f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 1000000; 774f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 4: 775f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 2000000; 776f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 11: 777f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 5500000; 778f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 12: 779f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 6000000; 780f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 18: 781f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 9000000; 782f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 22: 783f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 11000000; 784f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 24: 785f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 12000000; 786f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 36: 787f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 18000000; 788f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 44: 789f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 22000000; 790f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 48: 791f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 24000000; 792f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 66: 793f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 33000000; 794f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 72: 795f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 36000000; 796f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 96: 797f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 48000000; 798f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 108: 799f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 54000000; 800f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 801f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //ERROR UNKNOWN RATE 802f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return -1; 803f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 804f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 805f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 806f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Supported Rates format (size unit: byte) 807f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 808f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //| ElementID | Length | Supported Rates [7 Little Endian Info bits - 1 Flag bit] 809f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 1 1 1 - 8 810f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 811f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 812f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // stripped off already 813f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 814f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public void from(InformationElement ie) { 815e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 816e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart if (ie == null || ie.bytes == null || ie.bytes.length > 8 || ie.bytes.length < 1) { 817f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 818f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 819f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 820f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne try { 821f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (int i = 0; i < ie.bytes.length; i++) { 822f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne int rate = getRateFromByte(data.get()); 823f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (rate > 0) { 824f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates.add(rate); 825f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 826f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 827f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 828f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 829f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } catch (BufferUnderflowException e) { 830f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 831f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 832f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mValid = true; 833f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 834f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 835f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 836f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 837f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Lists the rates in a human readable string 838f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 839f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public String toString() { 840f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne StringBuilder sbuf = new StringBuilder(); 841f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (Integer rate : mRates) { 842f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne sbuf.append(String.format("%.1f", (double) rate / 1000000) + ", "); 843f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 844f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return sbuf.toString(); 845f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 846f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 8475d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills} 848