InformationElementUtil.java revision b86089a48fae8878b5a27533a116c97b0be6d0e7
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 264b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 265b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * This IE contained a bit field indicating the capabilities being advertised by the STA. 266b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * The size of the bit field (number of bytes) is indicated by the |Length| field in the IE. 267b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 268b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Refer to Section 8.4.2.29 in IEEE 802.11-2012 Spec for capability associated with each 269b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * bit. 270b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 271b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Here is the wire format of this IE: 272b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * | Element ID | Length | Capabilities | 273b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 1 1 n 274b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 2755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class ExtendedCapabilities { 2765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int RTT_RESP_ENABLE_BIT = 70; 277b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu private static final int SSID_UTF8_BIT = 48; 2785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 279b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public BitSet capabilitiesBitSet; 2805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 281b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 282b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @return true if SSID should be interpreted using UTF-8 encoding 283b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 284b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public boolean isStrictUtf8() { 285b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu return capabilitiesBitSet.get(SSID_UTF8_BIT); 2865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 288b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 289b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @return true if 802.11 MC RTT Response is enabled 290b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 291b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public boolean is80211McRTTResponder() { 292b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu return capabilitiesBitSet.get(RTT_RESP_ENABLE_BIT); 2935d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 295b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public ExtendedCapabilities() { 296b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = new BitSet(); 2975d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2985d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 299b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public ExtendedCapabilities(ExtendedCapabilities other) { 300b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = other.capabilitiesBitSet; 301b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu } 3025d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 303b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu /** 304b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * Parse an ExtendedCapabilities from the IE containing raw bytes. 305b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * 306b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu * @param ie The Information element data 307b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu */ 308b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu public void from(InformationElement ie) { 309b86089a48fae8878b5a27533a116c97b0be6d0e7Peter Qiu capabilitiesBitSet = BitSet.valueOf(ie.bytes); 3105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3123571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3133571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 3143571366ac36c70746b9f013ec2b54482861c9292Randy Pan * parse beacon to build the capabilities 3153571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 3163571366ac36c70746b9f013ec2b54482861c9292Randy Pan * This class is used to build the capabilities string of the scan results coming 3173571366ac36c70746b9f013ec2b54482861c9292Randy Pan * from HAL. It parses the ieee beacon's capability field, WPA and RSNE IE as per spec, 3183571366ac36c70746b9f013ec2b54482861c9292Randy Pan * and builds the ScanResult.capabilities String in a way that mirrors the values returned 3193571366ac36c70746b9f013ec2b54482861c9292Randy Pan * by wpa_supplicant. 3203571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 3213571366ac36c70746b9f013ec2b54482861c9292Randy Pan public static class Capabilities { 3229b5773d2805e8c6141ca75de272921a84941546bRandy Pan private static final int CAP_ESS_BIT_OFFSET = 0; 3233571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int CAP_PRIVACY_BIT_OFFSET = 4; 3243571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3253571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_VENDOR_OUI_TYPE_ONE = 0x01f25000; 3263571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short WPA_VENDOR_OUI_VERSION = 0x0001; 3273571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short RSNE_VERSION = 0x0001; 3283571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3293571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_EAP = 0x01f25000; 3303571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_PSK = 0x02f25000; 3313571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3323571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP = 0x01ac0f00; 3333571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK = 0x02ac0f00; 3343571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_EAP = 0x03ac0f00; 3353571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_PSK = 0x04ac0f00; 3363571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP_SHA256 = 0x05ac0f00; 3373571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK_SHA256 = 0x06ac0f00; 3383571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3394d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_NONE = 0x00f25000; 3404d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_TKIP = 0x02f25000; 3414d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int WPA_CIPHER_CCMP = 0x04f25000; 3424d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 3434d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_NONE = 0x00ac0f00; 3444d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_TKIP = 0x02ac0f00; 3454d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_CCMP = 0x04ac0f00; 3464d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private static final int RSN_CIPHER_NO_GROUP_ADDRESSED = 0x07ac0f00; 3474d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 348fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang public int protocol; 349fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang public ArrayList<Integer> keyManagement; 350fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang public ArrayList<Integer> pairwiseCipher; 351fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang public int groupCipher; 3524d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public boolean isESS; 3534d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public boolean isPrivacy; 3544d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 3553571366ac36c70746b9f013ec2b54482861c9292Randy Pan public Capabilities() { 3563571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3573571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3583571366ac36c70746b9f013ec2b54482861c9292Randy Pan // RSNE format (size unit: byte) 3593571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 3603571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | Version | Group Data Cipher Suite | 3613571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 2 4 3623571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 3633571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 3643571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | RSN Capabilities | 3653571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 2 3663571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | PMKID Count | PMKID List | Group Management Cipher Suite | 3673571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 16 * s 4 3683571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 3693571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 3703571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 3714d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private void parseRsnElement(InformationElement ie) { 3723571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 3733571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3743571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 3753571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 3763571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != RSNE_VERSION) { 3773571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 3784d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 3793571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3803571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3813571366ac36c70746b9f013ec2b54482861c9292Randy Pan // found the RSNE IE, hence start building the capability string 382fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang protocol = ScanResult.PROTOCOL_WPA2; 3834d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 3844d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // group data cipher suite 385fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang groupCipher = parseRsnCipher(buf.getInt()); 3863571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3873571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 3883571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 3893571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite list 3903571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 391fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang pairwiseCipher.add(parseRsnCipher(buf.getInt())); 3923571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3933571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3943571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 3953571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 3963571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 3973571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3983571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 3993571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 4003571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 4013571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP: 402fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_EAP); 4033571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4043571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK: 405fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_PSK); 4063571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4073571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_EAP: 408fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_FT_EAP); 4093571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4103571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_PSK: 411fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_FT_PSK); 4123571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4133571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP_SHA256: 414fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_EAP_SHA256); 4153571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4163571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK_SHA256: 417fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_PSK_SHA256); 4183571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4193571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 4203571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 4213571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4223571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4233571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4244d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // Default AKM 4254d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang if (keyManagement.isEmpty()) { 426fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_EAP); 4274d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 4283571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 4293571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse RSNE, buffer underflow"); 4304d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 4314d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 4324d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 433fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private static int parseWpaCipher(int cipher) { 4344d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang switch (cipher) { 4354d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_NONE: 436fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 4374d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_TKIP: 438fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_TKIP; 4394d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case WPA_CIPHER_CCMP: 440fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_CCMP; 4414d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang default: 442fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang Log.w("IE_Capabilities", "Unknown WPA cipher suite: " 443fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + Integer.toHexString(cipher)); 444fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 4454d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 4464d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 4474d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 448fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private static int parseRsnCipher(int cipher) { 4494d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang switch (cipher) { 4504d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_NONE: 451fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 4524d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_TKIP: 453fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_TKIP; 4544d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_CCMP: 455fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_CCMP; 4564d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang case RSN_CIPHER_NO_GROUP_ADDRESSED: 457fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NO_GROUP_ADDRESSED; 4584d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang default: 459fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang Log.w("IE_Capabilities", "Unknown RSN cipher suite: " 460fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + Integer.toHexString(cipher)); 461fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return ScanResult.CIPHER_NONE; 4623571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4633571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4643571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4653571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static boolean isWpaOneElement(InformationElement ie) { 4663571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 4673571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4683571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 4693571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA OUI and type 4703571366ac36c70746b9f013ec2b54482861c9292Randy Pan return (buf.getInt() == WPA_VENDOR_OUI_TYPE_ONE); 4713571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 4723571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse VSA IE, buffer underflow"); 4733571366ac36c70746b9f013ec2b54482861c9292Randy Pan return false; 4743571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4753571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4763571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4773571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA type 1 format (size unit: byte) 4783571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4793571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | OUI | Type | Version | 4803571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 3 1 2 4814d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // | Group Data Cipher Suite | 4824d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // 4 4833571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 4843571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 4853571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | 4863571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 4873571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4883571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 4893571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 4903571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4914d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang private void parseWpaOneElement(InformationElement ie) { 4923571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 4933571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4943571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 4953571366ac36c70746b9f013ec2b54482861c9292Randy Pan // skip WPA OUI and type parsing. isWpaOneElement() should have 4963571366ac36c70746b9f013ec2b54482861c9292Randy Pan // been called for verification before we reach here. 4973571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 4983571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4993571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 5003571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != WPA_VENDOR_OUI_VERSION) { 5013571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 5024d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 5033571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5043571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5054d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // start building the string 506fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang protocol = ScanResult.PROTOCOL_WPA; 5074d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 5083571366ac36c70746b9f013ec2b54482861c9292Randy Pan // group data cipher suite 509fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang groupCipher = parseWpaCipher(buf.getInt()); 5103571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5113571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 5123571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 5133571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise chipher suite list 5143571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 515fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang pairwiseCipher.add(parseWpaCipher(buf.getInt())); 5163571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5173571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5183571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 5193571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 5203571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 5213571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5223571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite list 5233571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 5243571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 5253571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 5263571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_EAP: 527fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_EAP); 5283571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 5293571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_PSK: 530fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_PSK); 5313571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 5323571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 5333571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 5343571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 5353571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5363571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5374d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang // Default AKM 5384d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang if (keyManagement.isEmpty()) { 539fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement.add(ScanResult.KEY_MGMT_EAP); 5404d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 5413571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 5423571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse type 1 WPA, buffer underflow"); 5433571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5443571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5453571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5463571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 5473571366ac36c70746b9f013ec2b54482861c9292Randy Pan * Parse the Information Element and the 16-bit Capability Information field 5484d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * to build the InformationElemmentUtil.capabilities object. 5493571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 5503571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param ies -- Information Element array 5513571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param beaconCap -- 16-bit Beacon Capability Information field 5523571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 5534d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang 5544d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public void from(InformationElement[] ies, BitSet beaconCap) { 555fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang protocol = ScanResult.PROTOCOL_NONE; 556fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang keyManagement = new ArrayList<Integer>(); 557fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang groupCipher = ScanResult.CIPHER_NONE; 558fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang pairwiseCipher = new ArrayList<Integer>(); 5593571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean rsneFound = false; 5603571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean wpaFound = false; 5613571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5623571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ies == null || beaconCap == null) { 5634d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang return; 5643571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5654d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang isESS = beaconCap.get(CAP_ESS_BIT_OFFSET); 5664d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang isPrivacy = beaconCap.get(CAP_PRIVACY_BIT_OFFSET); 5673571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (InformationElement ie : ies) { 5683571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_RSN) { 5693571366ac36c70746b9f013ec2b54482861c9292Randy Pan rsneFound = true; 5704d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang parseRsnElement(ie); 5713571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5723571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5733571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_VSA) { 5743571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (isWpaOneElement(ie)) { 5753571366ac36c70746b9f013ec2b54482861c9292Randy Pan wpaFound = true; 5764d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang parseWpaOneElement(ie); 5773571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5783571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5793571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 580fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 581fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 582fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String protocolToString(int protocol) { 583fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (protocol) { 584fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_NONE: 585fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 586fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_WPA: 587fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "WPA"; 588fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.PROTOCOL_WPA2: 589fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "WPA2"; 590fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 591fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 592fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 593fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 594fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 595fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String keyManagementToString(int akm) { 596fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (akm) { 597fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_NONE: 598fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 599fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_PSK: 600fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "PSK"; 601fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_EAP: 602fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "EAP"; 603fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_FT_EAP: 604fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "FT/EAP"; 605fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_FT_PSK: 606fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "FT/PSK"; 607fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_EAP_SHA256: 608fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "EAP-SHA256"; 609fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.KEY_MGMT_PSK_SHA256: 610fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "PSK-SHA256"; 611fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 612fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 613fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 614fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang } 615fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 616fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang private String cipherToString(int cipher) { 617fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang switch (cipher) { 618fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_NONE: 619fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "None"; 620fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_CCMP: 621fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "CCMP"; 622fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang case ScanResult.CIPHER_TKIP: 623fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "TKIP"; 624fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang default: 625fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang return "?"; 6263571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6274d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 6283571366ac36c70746b9f013ec2b54482861c9292Randy Pan 6294d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang /** 6304d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * Build the ScanResult.capabilities String. 6314d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * 6324d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang * @return security string that mirrors what wpa_supplicant generates 6334d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang */ 6344d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang public String generateCapabilitiesString() { 6354d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang String capabilities = ""; 636fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang // private Beacon without an RSNE or WPA IE, hence WEP0 637fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang boolean isWEP = (protocol == ScanResult.PROTOCOL_NONE) && isPrivacy; 638fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang 639fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang if (protocol != ScanResult.PROTOCOL_NONE || isWEP) { 640fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang capabilities += "[" + (isWEP ? "WEP" : protocolToString(protocol)); 6414d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang for (int i = 0; i < keyManagement.size(); i++) { 642fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang capabilities += ((i == 0) ? "-" : "+") 643fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang + keyManagementToString(keyManagement.get(i)); 6444d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 6454d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang for (int i = 0; i < pairwiseCipher.size(); i++) { 646fef4b474b74c838edf9d810bf13df757012571a3Ningyuan Wang capabilities += ((i == 0) ? "-" : "+") + cipherToString(pairwiseCipher.get(i)); 6474d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 6484d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang capabilities += "]"; 6494d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang } 6504d11585ede6636fee294ffb89e832e2f7f271c12Ningyuan Wang if (isESS) { 6519b5773d2805e8c6141ca75de272921a84941546bRandy Pan capabilities += "[ESS]"; 6529b5773d2805e8c6141ca75de272921a84941546bRandy Pan } 6533571366ac36c70746b9f013ec2b54482861c9292Randy Pan return capabilities; 6543571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 6553571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 656947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 657947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 658947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Parser for the Traffic Indication Map (TIM) Information Element (EID 5). This element will 659947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * only be present in scan results that are derived from a Beacon Frame, not from the more 660947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * plentiful probe responses. Call 'isValid()' after parsing, to ensure the results are correct. 661947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 662947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public static class TrafficIndicationMap { 663947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private static final int MAX_TIM_LENGTH = 254; 664947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private boolean mValid = false; 665947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mLength = 0; 666947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimCount = -1; 667947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //Negative DTIM Period means no TIM element was given this frame. 668947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimPeriod = -1; 669947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mBitmapControl = 0; 670947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 671947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 672947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Is this a valid TIM information element. 673947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 674947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public boolean isValid() { 675947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return mValid; 676947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 677947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 678947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Traffic Indication Map format (size unit: byte) 679947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 680947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //| ElementID | Length | DTIM Count | DTIM Period | BitmapControl | Partial Virtual Bitmap | 681947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 1 1 1 1 1 1 - 251 682947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 683947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 684947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // stripped off already 685947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 686947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public void from(InformationElement ie) { 687e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 688947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne if (ie == null || ie.bytes == null) return; 689947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mLength = ie.bytes.length; 690947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 691947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne try { 692947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimCount = data.get() & Constants.BYTE_MASK; 693947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimPeriod = data.get() & Constants.BYTE_MASK; 694947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mBitmapControl = data.get() & Constants.BYTE_MASK; 695947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //A valid TIM element must have atleast one more byte 696947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne data.get(); 697947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } catch (BufferUnderflowException e) { 698947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return; 699947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 70059f9a74676831ba4634b35d56a1e2bbe9bf4e322Glen Kuhne if (mLength <= MAX_TIM_LENGTH && mDtimPeriod > 0) { 701947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mValid = true; 702947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 703947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 704947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 705f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 706f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 707f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * This util class determines the 802.11 standard (a/b/g/n/ac) being used 708f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 709f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class WifiMode { 710f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_UNDEFINED = 0; // Unknown/undefined 711f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11A = 1; // 802.11a 712f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11B = 2; // 802.11b 713f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11G = 3; // 802.11g 714f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11N = 4; // 802.11n 715f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11AC = 5; // 802.11ac 716f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //<TODO> add support for 802.11ad and be more selective instead of defaulting to 11A 717f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 718f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 719f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Use frequency, max supported rate, and the existence of VHT, HT & ERP fields in scan 720f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * scan result to determine the 802.11 Wifi standard being used. 721f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 722f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int determineMode(int frequency, int maxRate, boolean foundVht, 723f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne boolean foundHt, boolean foundErp) { 724f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (foundVht) { 725f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11AC; 726f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundHt) { 727f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11N; 728f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundErp) { 729f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 730f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (frequency < 3000) { 731f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (maxRate < 24000000) { 732f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11B; 733f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 734f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 735f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 736f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 737f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11A; 738f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 739f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 740f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 741f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 742f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Map the wifiMode integer to its type, and output as String MODE_11<A/B/G/N/AC> 743f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 744f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static String toString(int mode) { 745f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(mode) { 746f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11A: 747f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11A"; 748f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11B: 749f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11B"; 750f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11G: 751f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11G"; 752f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11N: 753f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11N"; 754f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11AC: 755f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11AC"; 756f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 757f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_UNDEFINED"; 758f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 759f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 760f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 761f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 762f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 763f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Parser for both the Supported Rates & Extended Supported Rates Information Elements 764f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 765f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class SupportedRates { 766f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MASK = 0x7F; // 0111 1111 767f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean mValid = false; 768f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public ArrayList<Integer> mRates; 769f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 770f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public SupportedRates() { 771f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates = new ArrayList<Integer>(); 772f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 773f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 774f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 775f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Is this a valid Supported Rates information element. 776f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 777f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean isValid() { 778f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return mValid; 779f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 780f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 781f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 782f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * get the Rate in bits/s from associated byteval 783f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 784f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int getRateFromByte(int byteVal) { 785f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne byteVal &= MASK; 786f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(byteVal) { 787f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 2: 788f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 1000000; 789f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 4: 790f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 2000000; 791f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 11: 792f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 5500000; 793f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 12: 794f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 6000000; 795f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 18: 796f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 9000000; 797f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 22: 798f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 11000000; 799f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 24: 800f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 12000000; 801f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 36: 802f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 18000000; 803f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 44: 804f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 22000000; 805f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 48: 806f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 24000000; 807f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 66: 808f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 33000000; 809f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 72: 810f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 36000000; 811f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 96: 812f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 48000000; 813f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 108: 814f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 54000000; 815f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 816f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //ERROR UNKNOWN RATE 817f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return -1; 818f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 819f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 820f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 821f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Supported Rates format (size unit: byte) 822f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 823f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //| ElementID | Length | Supported Rates [7 Little Endian Info bits - 1 Flag bit] 824f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 1 1 1 - 8 825f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 826f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 827f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // stripped off already 828f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 829f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public void from(InformationElement ie) { 830e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 831e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart if (ie == null || ie.bytes == null || ie.bytes.length > 8 || ie.bytes.length < 1) { 832f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 833f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 834f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 835f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne try { 836f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (int i = 0; i < ie.bytes.length; i++) { 837f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne int rate = getRateFromByte(data.get()); 838f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (rate > 0) { 839f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates.add(rate); 840f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 841f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 842f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 843f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 844f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } catch (BufferUnderflowException e) { 845f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 846f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 847f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mValid = true; 848f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 849f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 850f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 851f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 852f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Lists the rates in a human readable string 853f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 854f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public String toString() { 855f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne StringBuilder sbuf = new StringBuilder(); 856f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (Integer rate : mRates) { 857f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne sbuf.append(String.format("%.1f", (double) rate / 1000000) + ", "); 858f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 859f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return sbuf.toString(); 860f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 861f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 8625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills} 863