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