InformationElementUtil.java revision e7399556522efdd3f137aba31c49cbb8d95c59d6
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 183571366ac36c70746b9f013ec2b54482861c9292Randy Panimport static com.android.server.wifi.anqp.Constants.getInteger; 193571366ac36c70746b9f013ec2b54482861c9292Randy Pan 205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport android.net.wifi.ScanResult.InformationElement; 215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport android.util.Log; 225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport com.android.server.wifi.anqp.Constants; 235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport com.android.server.wifi.hotspot2.NetworkDetail; 245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport java.net.ProtocolException; 253571366ac36c70746b9f013ec2b54482861c9292Randy Panimport java.nio.BufferUnderflowException; 265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport java.nio.ByteBuffer; 275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport java.nio.ByteOrder; 285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport java.util.ArrayList; 293571366ac36c70746b9f013ec2b54482861c9292Randy Panimport java.util.BitSet; 305d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willspublic class InformationElementUtil { 325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static InformationElement[] parseInformationElements(byte[] bytes) { 34da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein if (bytes == null) { 35da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein return new InformationElement[0]; 36da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein } 375d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); 385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 395d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ArrayList<InformationElement> infoElements = new ArrayList<>(); 405d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills boolean found_ssid = false; 415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills while (data.remaining() > 1) { 425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int eid = data.get() & Constants.BYTE_MASK; 435d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int elementLength = data.get() & Constants.BYTE_MASK; 445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 453571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (elementLength > data.remaining() || (eid == InformationElement.EID_SSID 463571366ac36c70746b9f013ec2b54482861c9292Randy Pan && found_ssid)) { 47da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // APs often pad the data with bytes that happen to match that of the EID_SSID 48da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // marker. This is not due to a known issue for APs to incorrectly send the SSID 49da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // name multiple times. 505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 515d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 523571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (eid == InformationElement.EID_SSID) { 535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills found_ssid = true; 545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills InformationElement ie = new InformationElement(); 575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ie.id = eid; 585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ie.bytes = new byte[elementLength]; 595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills data.get(ie.bytes); 605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills infoElements.add(ie); 615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return infoElements.toArray(new InformationElement[infoElements.size()]); 635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class BssLoad { 675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int stationCount = 0; 685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int channelUtilization = 0; 695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int capacity = 0; 705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 715d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 723571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_BSS_LOAD) { 735d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not BSS_LOAD, : " + ie.id); 745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length != 5) { 763571366ac36c70746b9f013ec2b54482861c9292Randy Pan throw new IllegalArgumentException("BSS Load element length is not 5: " 773571366ac36c70746b9f013ec2b54482861c9292Randy Pan + ie.bytes.length); 785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 795d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills stationCount = data.getShort() & Constants.SHORT_MASK; 815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills channelUtilization = data.get() & Constants.BYTE_MASK; 825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills capacity = data.getShort() & Constants.SHORT_MASK; 835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class HtOperation { 875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int secondChannelOffset = 0; 885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 895d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getChannelWidth() { 903571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (secondChannelOffset != 0) { 915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 1; 923571366ac36c70746b9f013ec2b54482861c9292Randy Pan } else { 935d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 955d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 965d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 975d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq0(int primaryFrequency) { 989f743918a412fec9ad5a0386fbf6cf0361313f58xinhe //40 MHz 999f743918a412fec9ad5a0386fbf6cf0361313f58xinhe if (secondChannelOffset != 0) { 1005d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (secondChannelOffset == 1) { 1019f743918a412fec9ad5a0386fbf6cf0361313f58xinhe return primaryFrequency + 10; 1025d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else if (secondChannelOffset == 3) { 1039f743918a412fec9ad5a0386fbf6cf0361313f58xinhe return primaryFrequency - 10; 1045d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 1055d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills Log.e("HtOperation", "Error on secondChannelOffset: " + secondChannelOffset); 1065d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1075d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1085d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 1095d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1143571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_HT_OPERATION) { 1155d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not HT_OPERATION, : " + ie.id); 1165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills secondChannelOffset = ie.bytes[1] & 0x3; 1185d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1195d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class VhtOperation { 1225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int channelMode = 0; 1235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int centerFreqIndex1 = 0; 1245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int centerFreqIndex2 = 0; 1255d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean isValid() { 1275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return channelMode != 0; 1285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1305d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getChannelWidth() { 1315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return channelMode + 1; 1325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq0() { 1355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills //convert channel index to frequency in MHz, channel 36 is 5180MHz 1365d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return (centerFreqIndex1 - 36) * 5 + 5180; 1375d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1395d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq1() { 1403571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (channelMode > 1) { //160MHz 1415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return (centerFreqIndex2 - 36) * 5 + 5180; 1425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 1435d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1475d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1483571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_VHT_OPERATION) { 1495d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not VHT_OPERATION, : " + ie.id); 1505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1515d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills channelMode = ie.bytes[0] & Constants.BYTE_MASK; 1525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills centerFreqIndex1 = ie.bytes[1] & Constants.BYTE_MASK; 1535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills centerFreqIndex2 = ie.bytes[2] & Constants.BYTE_MASK; 1545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class Interworking { 1585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public NetworkDetail.Ant ant = null; 1595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean internet = false; 1605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public long hessid = 0L; 1615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1633571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_INTERWORKING) { 1645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not INTERWORKING, : " + ie.id); 1655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 1675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int anOptions = data.get() & Constants.BYTE_MASK; 1685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ant = NetworkDetail.Ant.values()[anOptions & 0x0f]; 1695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills internet = (anOptions & 0x10) != 0; 170e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // There are only three possible lengths for the Interworking IE: 171e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 1: Access Network Options only 172e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 3: Access Network Options & Venue Info 173e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 7: Access Network Options & HESSID 174e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan // Len 9: Access Network Options, Venue Info, & HESSID 175e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan if (ie.bytes.length != 1 176e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan && ie.bytes.length != 3 177e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan && ie.bytes.length != 7 178e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan && ie.bytes.length != 9) { 179e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan throw new IllegalArgumentException( 180e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan "Bad Interworking element length: " + ie.bytes.length); 1815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 182e7399556522efdd3f137aba31c49cbb8d95c59d6Samuel Tan 1835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length == 7 || ie.bytes.length == 9) { 1845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hessid = getInteger(data, ByteOrder.BIG_ENDIAN, 6); 1855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1895d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class RoamingConsortium { 1905d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int anqpOICount = 0; 1915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public long[] roamingConsortiums = null; 1925d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1935d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1943571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_ROAMING_CONSORTIUM) { 1953571366ac36c70746b9f013ec2b54482861c9292Randy Pan throw new IllegalArgumentException("Element id is not ROAMING_CONSORTIUM, : " 1963571366ac36c70746b9f013ec2b54482861c9292Randy Pan + ie.id); 1975d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1985d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 1995d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpOICount = data.get() & Constants.BYTE_MASK; 2005d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2015d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi12Length = data.get() & Constants.BYTE_MASK; 2025d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi1Length = oi12Length & Constants.NIBBLE_MASK; 2035d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi2Length = (oi12Length >>> 4) & Constants.NIBBLE_MASK; 2045d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi3Length = ie.bytes.length - 2 - oi1Length - oi2Length; 2055d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oiCount = 0; 2065d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0) { 2075d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2085d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0) { 2095d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0) { 2115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2145d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2155d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums = new long[oiCount]; 2165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0 && roamingConsortiums.length > 0) { 2175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[0] = 2185d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills getInteger(data, ByteOrder.BIG_ENDIAN, oi1Length); 2195d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0 && roamingConsortiums.length > 1) { 2215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[1] = 2225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills getInteger(data, ByteOrder.BIG_ENDIAN, oi2Length); 2235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0 && roamingConsortiums.length > 2) { 2255d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[2] = 2265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills getInteger(data, ByteOrder.BIG_ENDIAN, oi3Length); 2275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2305d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class Vsa { 2325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int ANQP_DOMID_BIT = 0x04; 2335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public NetworkDetail.HSRelease hsRelease = null; 2355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int anqpDomainID = 0; // No domain ID treated the same as a 0; unique info per AP. 2365d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2375d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2395d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length >= 5 && data.getInt() == Constants.HS20_FRAME_PREFIX) { 2405d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int hsConf = data.get() & Constants.BYTE_MASK; 2415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills switch ((hsConf >> 4) & Constants.NIBBLE_MASK) { 2425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 0: 2435d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R1; 2445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 2455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 1: 2465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R2; 2475d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 2485d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills default: 2495d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.Unknown; 2505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 2515d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if ((hsConf & ANQP_DOMID_BIT) != 0) { 2535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length < 7) { 2545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException( 2555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills "HS20 indication element too short: " + ie.bytes.length); 2565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpDomainID = data.getShort() & Constants.SHORT_MASK; 2585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class ExtendedCapabilities { 2645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int RTT_RESP_ENABLE_BIT = 70; 2655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final long SSID_UTF8_BIT = 0x0001000000000000L; 2665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public Long extendedCapabilities = null; 2685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean is80211McRTTResponder = false; 2695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public ExtendedCapabilities() { 2715d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2735d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public ExtendedCapabilities(ExtendedCapabilities other) { 2745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills extendedCapabilities = other.extendedCapabilities; 2755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills is80211McRTTResponder = other.is80211McRTTResponder; 2765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean isStrictUtf8() { 2795d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return extendedCapabilities != null && (extendedCapabilities & SSID_UTF8_BIT) != 0; 2805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills extendedCapabilities = 2855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills Constants.getInteger(data, ByteOrder.LITTLE_ENDIAN, ie.bytes.length); 2865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int index = RTT_RESP_ENABLE_BIT / 8; 2885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills byte offset = RTT_RESP_ENABLE_BIT % 8; 2893571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.bytes.length < index + 1) { 2905d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills is80211McRTTResponder = false; 2915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 2923571366ac36c70746b9f013ec2b54482861c9292Randy Pan is80211McRTTResponder = (ie.bytes[index] & ((byte) 0x1 << offset)) != 0; 2935d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2955d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2963571366ac36c70746b9f013ec2b54482861c9292Randy Pan 2973571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 2983571366ac36c70746b9f013ec2b54482861c9292Randy Pan * parse beacon to build the capabilities 2993571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 3003571366ac36c70746b9f013ec2b54482861c9292Randy Pan * This class is used to build the capabilities string of the scan results coming 3013571366ac36c70746b9f013ec2b54482861c9292Randy Pan * from HAL. It parses the ieee beacon's capability field, WPA and RSNE IE as per spec, 3023571366ac36c70746b9f013ec2b54482861c9292Randy Pan * and builds the ScanResult.capabilities String in a way that mirrors the values returned 3033571366ac36c70746b9f013ec2b54482861c9292Randy Pan * by wpa_supplicant. 3043571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 3053571366ac36c70746b9f013ec2b54482861c9292Randy Pan public static class Capabilities { 3069b5773d2805e8c6141ca75de272921a84941546bRandy Pan private static final int CAP_ESS_BIT_OFFSET = 0; 3073571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int CAP_PRIVACY_BIT_OFFSET = 4; 3083571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3093571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_VENDOR_OUI_TYPE_ONE = 0x01f25000; 3103571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short WPA_VENDOR_OUI_VERSION = 0x0001; 3113571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short RSNE_VERSION = 0x0001; 3123571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3133571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_EAP = 0x01f25000; 3143571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_PSK = 0x02f25000; 3153571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3163571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP = 0x01ac0f00; 3173571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK = 0x02ac0f00; 3183571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_EAP = 0x03ac0f00; 3193571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_PSK = 0x04ac0f00; 3203571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP_SHA256 = 0x05ac0f00; 3213571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK_SHA256 = 0x06ac0f00; 3223571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3233571366ac36c70746b9f013ec2b54482861c9292Randy Pan public Capabilities() { 3243571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3253571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3263571366ac36c70746b9f013ec2b54482861c9292Randy Pan // RSNE format (size unit: byte) 3273571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 3283571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | Version | Group Data Cipher Suite | 3293571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 2 4 3303571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 3313571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 3323571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | RSN Capabilities | 3333571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 2 3343571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | PMKID Count | PMKID List | Group Management Cipher Suite | 3353571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 16 * s 4 3363571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 3373571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 3383571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 3393571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static String parseRsnElement(InformationElement ie) { 3403571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 3413571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3423571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 3433571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 3443571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != RSNE_VERSION) { 3453571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 3463571366ac36c70746b9f013ec2b54482861c9292Randy Pan return null; 3473571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3483571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3493571366ac36c70746b9f013ec2b54482861c9292Randy Pan // group data cipher suite 3503571366ac36c70746b9f013ec2b54482861c9292Randy Pan // here we simply advance the buffer position 3513571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 3523571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3533571366ac36c70746b9f013ec2b54482861c9292Randy Pan // found the RSNE IE, hence start building the capability string 3543571366ac36c70746b9f013ec2b54482861c9292Randy Pan String security = "[WPA2"; 3553571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3563571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 3573571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 3583571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3593571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite list 3603571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 3613571366ac36c70746b9f013ec2b54482861c9292Randy Pan // here we simply advance the buffer position 3623571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 3633571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3643571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3653571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 3663571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 3673571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 3683571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3693571366ac36c70746b9f013ec2b54482861c9292Randy Pan // parse AKM suite list 3703571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (akmCount == 0) { 3713571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += "-EAP"; //default AKM 3723571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3733571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean found = false; 3743571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 3753571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 3763571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 3773571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP: 3783571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "EAP"; 3793571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 3803571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3813571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK: 3823571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "PSK"; 3833571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 3843571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3853571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_EAP: 3863571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "FT/EAP"; 3873571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 3883571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3893571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_PSK: 3903571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "FT/PSK"; 3913571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 3923571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3933571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP_SHA256: 3943571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "EAP-SHA256"; 3953571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 3963571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3973571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK_SHA256: 3983571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "PSK-SHA256"; 3993571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 4003571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4013571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 4023571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 4033571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4043571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4053571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4063571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4073571366ac36c70746b9f013ec2b54482861c9292Randy Pan // we parsed what we want at this point 4083571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += "]"; 4093571366ac36c70746b9f013ec2b54482861c9292Randy Pan return security; 4103571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 4113571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse RSNE, buffer underflow"); 4123571366ac36c70746b9f013ec2b54482861c9292Randy Pan return null; 4133571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4143571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4153571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4163571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static boolean isWpaOneElement(InformationElement ie) { 4173571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 4183571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4193571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 4203571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA OUI and type 4213571366ac36c70746b9f013ec2b54482861c9292Randy Pan return (buf.getInt() == WPA_VENDOR_OUI_TYPE_ONE); 4223571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 4233571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse VSA IE, buffer underflow"); 4243571366ac36c70746b9f013ec2b54482861c9292Randy Pan return false; 4253571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4263571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4273571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4283571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA type 1 format (size unit: byte) 4293571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4303571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | OUI | Type | Version | 4313571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 3 1 2 4323571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 4333571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 4343571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | 4353571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 4363571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4373571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 4383571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 4393571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4403571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static String parseWpaOneElement(InformationElement ie) { 4413571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 4423571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4433571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 4443571366ac36c70746b9f013ec2b54482861c9292Randy Pan // skip WPA OUI and type parsing. isWpaOneElement() should have 4453571366ac36c70746b9f013ec2b54482861c9292Randy Pan // been called for verification before we reach here. 4463571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 4473571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4483571366ac36c70746b9f013ec2b54482861c9292Randy Pan // start building the string 4493571366ac36c70746b9f013ec2b54482861c9292Randy Pan String security = "[WPA"; 4503571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4513571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 4523571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != WPA_VENDOR_OUI_VERSION) { 4533571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 4543571366ac36c70746b9f013ec2b54482861c9292Randy Pan return null; 4553571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4563571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4573571366ac36c70746b9f013ec2b54482861c9292Randy Pan // group data cipher suite 4583571366ac36c70746b9f013ec2b54482861c9292Randy Pan // here we simply advance buffer position 4593571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 4603571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4613571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 4623571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 4633571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4643571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise chipher suite list 4653571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 4663571366ac36c70746b9f013ec2b54482861c9292Randy Pan // here we simply advance buffer position 4673571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 4683571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4693571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4703571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 4713571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 4723571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 4733571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4743571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite list 4753571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (akmCount == 0) { 4763571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += "-EAP"; //default AKM 4773571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4783571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean found = false; 4793571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 4803571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 4813571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 4823571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_EAP: 4833571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "EAP"; 4843571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 4853571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4863571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_PSK: 4873571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "PSK"; 4883571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 4893571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4903571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 4913571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 4923571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4933571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4943571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4953571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4963571366ac36c70746b9f013ec2b54482861c9292Randy Pan // we parsed what we want at this point 4973571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += "]"; 4983571366ac36c70746b9f013ec2b54482861c9292Randy Pan return security; 4993571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 5003571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse type 1 WPA, buffer underflow"); 5013571366ac36c70746b9f013ec2b54482861c9292Randy Pan return null; 5023571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5033571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5043571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5053571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 5063571366ac36c70746b9f013ec2b54482861c9292Randy Pan * Parse the Information Element and the 16-bit Capability Information field 5073571366ac36c70746b9f013ec2b54482861c9292Randy Pan * to build the ScanResult.capabilities String. 5083571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 5093571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param ies -- Information Element array 5103571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param beaconCap -- 16-bit Beacon Capability Information field 5113571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @return security string that mirrors what wpa_supplicant generates 5123571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 5133571366ac36c70746b9f013ec2b54482861c9292Randy Pan public static String buildCapabilities(InformationElement[] ies, BitSet beaconCap) { 5143571366ac36c70746b9f013ec2b54482861c9292Randy Pan String capabilities = ""; 5153571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean rsneFound = false; 5163571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean wpaFound = false; 5173571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5183571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ies == null || beaconCap == null) { 5193571366ac36c70746b9f013ec2b54482861c9292Randy Pan return capabilities; 5203571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5213571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5229b5773d2805e8c6141ca75de272921a84941546bRandy Pan boolean ess = beaconCap.get(CAP_ESS_BIT_OFFSET); 5233571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean privacy = beaconCap.get(CAP_PRIVACY_BIT_OFFSET); 5243571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5253571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (InformationElement ie : ies) { 5263571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_RSN) { 5273571366ac36c70746b9f013ec2b54482861c9292Randy Pan rsneFound = true; 5283571366ac36c70746b9f013ec2b54482861c9292Randy Pan capabilities += parseRsnElement(ie); 5293571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5303571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5313571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_VSA) { 5323571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (isWpaOneElement(ie)) { 5333571366ac36c70746b9f013ec2b54482861c9292Randy Pan wpaFound = true; 5343571366ac36c70746b9f013ec2b54482861c9292Randy Pan capabilities += parseWpaOneElement(ie); 5353571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5363571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5373571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5383571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5393571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (!rsneFound && !wpaFound && privacy) { 5403571366ac36c70746b9f013ec2b54482861c9292Randy Pan //private Beacon without an RSNE or WPA IE, hence WEP0 5413571366ac36c70746b9f013ec2b54482861c9292Randy Pan capabilities += "[WEP]"; 5423571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5433571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5449b5773d2805e8c6141ca75de272921a84941546bRandy Pan if (ess) { 5459b5773d2805e8c6141ca75de272921a84941546bRandy Pan capabilities += "[ESS]"; 5469b5773d2805e8c6141ca75de272921a84941546bRandy Pan } 5479b5773d2805e8c6141ca75de272921a84941546bRandy Pan 5483571366ac36c70746b9f013ec2b54482861c9292Randy Pan return capabilities; 5493571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5503571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 551947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 552947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 553947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Parser for the Traffic Indication Map (TIM) Information Element (EID 5). This element will 554947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * only be present in scan results that are derived from a Beacon Frame, not from the more 555947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * plentiful probe responses. Call 'isValid()' after parsing, to ensure the results are correct. 556947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 557947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public static class TrafficIndicationMap { 558947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private static final int MAX_TIM_LENGTH = 254; 559947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne private boolean mValid = false; 560947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mLength = 0; 561947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimCount = -1; 562947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //Negative DTIM Period means no TIM element was given this frame. 563947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mDtimPeriod = -1; 564947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public int mBitmapControl = 0; 565947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 566947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne /** 567947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne * Is this a valid TIM information element. 568947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne */ 569947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public boolean isValid() { 570947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return mValid; 571947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 572947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne 573947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Traffic Indication Map format (size unit: byte) 574947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 575947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //| ElementID | Length | DTIM Count | DTIM Period | BitmapControl | Partial Virtual Bitmap | 576947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 1 1 1 1 1 1 - 251 577947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 578947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 579947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // stripped off already 580947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne // 581947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne public void from(InformationElement ie) { 582e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 583947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne if (ie == null || ie.bytes == null) return; 584947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mLength = ie.bytes.length; 585947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 586947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne try { 587947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimCount = data.get() & Constants.BYTE_MASK; 588947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mDtimPeriod = data.get() & Constants.BYTE_MASK; 589947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mBitmapControl = data.get() & Constants.BYTE_MASK; 590947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne //A valid TIM element must have atleast one more byte 591947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne data.get(); 592947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } catch (BufferUnderflowException e) { 593947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne return; 594947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 595947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne if (mLength <= MAX_TIM_LENGTH) { 596947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne mValid = true; 597947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 598947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 599947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne } 600f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 601f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 602f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * This util class determines the 802.11 standard (a/b/g/n/ac) being used 603f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 604f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class WifiMode { 605f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_UNDEFINED = 0; // Unknown/undefined 606f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11A = 1; // 802.11a 607f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11B = 2; // 802.11b 608f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11G = 3; // 802.11g 609f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11N = 4; // 802.11n 610f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MODE_11AC = 5; // 802.11ac 611f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //<TODO> add support for 802.11ad and be more selective instead of defaulting to 11A 612f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 613f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 614f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Use frequency, max supported rate, and the existence of VHT, HT & ERP fields in scan 615f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * scan result to determine the 802.11 Wifi standard being used. 616f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 617f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int determineMode(int frequency, int maxRate, boolean foundVht, 618f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne boolean foundHt, boolean foundErp) { 619f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (foundVht) { 620f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11AC; 621f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundHt) { 622f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11N; 623f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (foundErp) { 624f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 625f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else if (frequency < 3000) { 626f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (maxRate < 24000000) { 627f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11B; 628f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 629f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11G; 630f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 631f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 632f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return MODE_11A; 633f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 634f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 635f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 636f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 637f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Map the wifiMode integer to its type, and output as String MODE_11<A/B/G/N/AC> 638f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 639f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static String toString(int mode) { 640f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(mode) { 641f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11A: 642f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11A"; 643f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11B: 644f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11B"; 645f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11G: 646f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11G"; 647f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11N: 648f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11N"; 649f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case MODE_11AC: 650f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_11AC"; 651f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 652f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return "MODE_UNDEFINED"; 653f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 654f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 655f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 656f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 657f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 658f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Parser for both the Supported Rates & Extended Supported Rates Information Elements 659f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 660f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static class SupportedRates { 661f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static final int MASK = 0x7F; // 0111 1111 662f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean mValid = false; 663f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public ArrayList<Integer> mRates; 664f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 665f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public SupportedRates() { 666f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates = new ArrayList<Integer>(); 667f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 668f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 669f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 670f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Is this a valid Supported Rates information element. 671f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 672f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public boolean isValid() { 673f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return mValid; 674f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 675f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 676f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 677f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * get the Rate in bits/s from associated byteval 678f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 679f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public static int getRateFromByte(int byteVal) { 680f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne byteVal &= MASK; 681f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne switch(byteVal) { 682f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 2: 683f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 1000000; 684f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 4: 685f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 2000000; 686f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 11: 687f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 5500000; 688f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 12: 689f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 6000000; 690f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 18: 691f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 9000000; 692f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 22: 693f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 11000000; 694f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 24: 695f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 12000000; 696f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 36: 697f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 18000000; 698f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 44: 699f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 22000000; 700f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 48: 701f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 24000000; 702f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 66: 703f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 33000000; 704f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 72: 705f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 36000000; 706f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 96: 707f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 48000000; 708f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne case 108: 709f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return 54000000; 710f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne default: 711f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //ERROR UNKNOWN RATE 712f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return -1; 713f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 714f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 715f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 716f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Supported Rates format (size unit: byte) 717f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 718f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne //| ElementID | Length | Supported Rates [7 Little Endian Info bits - 1 Flag bit] 719f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 1 1 1 - 8 720f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 721f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // Note: InformationElement.bytes has 'Element ID' and 'Length' 722f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // stripped off already 723f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne // 724f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public void from(InformationElement ie) { 725e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart mValid = false; 726e367514651d7f888dda870fb472eea6bcfd9ec5dPaul Stewart if (ie == null || ie.bytes == null || ie.bytes.length > 8 || ie.bytes.length < 1) { 727f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 728f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 729f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 730f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne try { 731f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (int i = 0; i < ie.bytes.length; i++) { 732f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne int rate = getRateFromByte(data.get()); 733f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne if (rate > 0) { 734f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mRates.add(rate); 735f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } else { 736f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 737f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 738f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 739f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } catch (BufferUnderflowException e) { 740f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 741f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 742f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne mValid = true; 743f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return; 744f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 745f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne 746f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne /** 747f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne * Lists the rates in a human readable string 748f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne */ 749f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne public String toString() { 750f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne StringBuilder sbuf = new StringBuilder(); 751f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne for (Integer rate : mRates) { 752f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne sbuf.append(String.format("%.1f", (double) rate / 1000000) + ", "); 753f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 754f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne return sbuf.toString(); 755f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 756f5cc6a0c7ede374b33de1cf5156bf149e2e76c13Glen Kuhne } 7575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills} 758